diff options
| author | Tim <timothyasir@gluster.com> | 2011-08-01 13:26:55 +0530 |
|---|---|---|
| committer | Tim <timothyasir@gluster.com> | 2011-08-01 13:26:55 +0530 |
| commit | b6dc76c7dad5dfc695b8f875e770a17c93e9d318 (patch) | |
| tree | 3dbf1cc296953cab941e1247863bb98a93dbd957 /src/com.gluster.storage.management.gateway.scripts | |
| parent | 65bb504695643445293726656a5b79427da06b14 (diff) | |
| parent | 0d12b25f91cfcbb09687d774389d85b8c8ffa249 (diff) | |
Merge remote branch 'upstream/master'
Diffstat (limited to 'src/com.gluster.storage.management.gateway.scripts')
48 files changed, 7308 insertions, 0 deletions
diff --git a/src/com.gluster.storage.management.gateway.scripts/.project b/src/com.gluster.storage.management.gateway.scripts/.project new file mode 100644 index 00000000..110db62b --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>com.gluster.storage.management.gateway.scripts</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.python.pydev.PyDevBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.python.pydev.pythonNature</nature> + </natures> +</projectDescription> diff --git a/src/com.gluster.storage.management.gateway.scripts/.pydevproject b/src/com.gluster.storage.management.gateway.scripts/.pydevproject new file mode 100644 index 00000000..c327cd69 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/.pydevproject @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?eclipse-pydev version="1.0"?> + +<pydev_project> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 3.0</pydev_property> +<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> +<path>/com.gluster.storage.management.gateway.scripts/src</path> +</pydev_pathproperty> +</pydev_project> diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Commands.py b/src/com.gluster.storage.management.gateway.scripts/src/Commands.py new file mode 100644 index 00000000..c728b565 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Commands.py @@ -0,0 +1,78 @@ +COMMAND_CREATE_VOLUME = "create-volume" +COMMAND_DELETE_VOLUME = "delete-volume" +COMMAND_START_VOLUME = "start-volume" +COMMAND_STOP_VOLUME = "stop-volume" +COMMAND_GET_VOLUME_HEALTH_STATUS = "get-volume-health-status" +COMMAND_GET_VOLUME_LIST = "get-volume-list" +COMMAND_GET_VOLUME_LOG = "get-volume-log" +COMMAND_CLEAR_VOLUME_LOGS = "clear-volume-logs" +COMMAND_GET_VOLUME_PROPERTY = "get-volume-property" +COMMAND_SET_VOLUME_PROPERTY = "set-volume-property" +COMMAND_GET_VOLUME_STATUS = "get-volume-status" +COMMAND_DOWNLOAD_VOLUME_LOGS = "download-volume-logs" +COMMAND_DELETE_SERVER = "delete-server" +COMMAND_GET_SERVER_DATE = "get-server-date" +COMMAND_GET_SERVER_VERSION_INFO = "get-server-version-info" +COMMAND_GET_INSTALLER_INFO = "get-installer-info" +COMMAND_GET_SERVER_LIST = "get-server-list" +COMMAND_GET_SERVER_SERVICE_STATUS = "get-server-service-status" +COMMAND_GET_STORAGE_SERVER_POOL_INFO = "get-storage-server-pool-info" +COMMAND_INSTALL_SERVER_BACKGROUND = "install-server-background" +COMMAND_PREPARE_DATA_DISK_BACKGROUND = "prepare-data-disk-background" +COMMAND_SET_SERVER_DATE = "set-server-date" +COMMAND_SET_SERVER_NETWORK_CONFIG = "set-server-network-config" +COMMAND_SET_STORAGE_SERVER_POOL_INFO = "set-storage-server-pool-info" +COMMAND_GET_SERVER_NETWORK_CONFIG = "get-server-network-config" +COMMAND_INSTALL_SERVER_STATUS = "install-server-status" +COMMAND_GET_SERVER_DISK_LIST = "get-server-disk-list" +COMMAND_PREPARE_DATA_DISK_STATUS = "prepare-data-disk-status" +COMMAND_GET_SERVER_SYSTEM_RESOURCE = "get-server-system-resource" +COMMAND_GET_SERVER_RESOURCE_RRD = "get-server-resource-rrd" +COMMAND_RUN_SERVER_SERVICE = "run-server-service" +COMMAND_SHUTDOWN_SERVER = "shutdown-server" +COMMAND_GET_SERVER_STATUS = "get-server-status" +COMMAND_GET_SERVER_LOG = "get-server-log" +COMMAND_DOWNLOAD_SERVER_LOGS = "download-server-logs" +COMMAND_CLEAR_SERVER_LOGS = "clear-server-logs" +COMMAND_GET_SERVER_RESOURCE_RRD = "get-server-resource-rrd" +COMMAND_GET_GSN_USER_INFO = "get-gsn-user-info" +COMMAND_SET_GSN_USER_INFO = "set-gsn-user-info" +COMMAND_GET_GLUSTER_UPDATE_INFO = "get-gluster-update-info" +COMMAND_DOWNLOAD_GLUSTER_UPDATE_BACKGROUND = "download-gluster-update-background" +COMMAND_DOWNLOAD_GLUSTER_UPDATE_STATUS = "download-gluster-update-status" +COMMAND_INSTALL_GLUSTER_UPDATE = "install-gluster-update" +COMMAND_EXPORT_CONFIG = "export-config" +COMMAND_IMPORT_CONFIG = "import-config" +COMMAND_SET_SYSTEM_PASSWORD = "set-system-password" +COMMAND_GET_SERVER_VOLUME_LIST = "get-server-volume-list" +COMMAND_RECONFIGURE_VOLUME = "reconfigure-volume" +COMMAND_SET_SERVER_DIRECTORY_SERVICE_CONFIG = "set-server-directory-service-config" +COMMAND_GET_SERVER_DIRECTORY_SERVICE_CONFIG = "get-server-directory-service-config" +COMMAND_JOIN_SERVER_TO_DIRECTORY_SERVICE = "join-server-to-directory-service" +COMMAND_SET_SERVER_TIME_CONFIG = "set-server-time-config" +COMMAND_GET_SERVER_TIME_CONFIG = "get-server-time-config" +COMMAND_LOGIN = "login" +COMMAND_LOGOUT = "logout" +COMMAND_GET_LOGIN_STATUS = "get-login-status" +COMMAND_GET_SERVER_TRANSPORT_LIST = "get-server-transport-list" +COMMAND_ADD_SERVER_PARTITION = "add-server-partition" +COMMAND_ADD_VOLUME_USER = "add-volume-user" +COMMAND_GET_PARTITION_VOLUME_LIST = "get-partition-volume-list" +COMMAND_GET_VOLUME_USER_INFO = "get-volume-user-info" +COMMAND_GET_VOLUME_USER_LIST = "get-volume-user-list" +COMMAND_MIGRATE_PARTITION_BACKGROUND = "migrate-partition-background" +COMMAND_MIGRATE_PARTITION_STATUS = "migrate-partition-status" +COMMAND_MIGRATE_VOLUME_SERVER_PARTITION_BACKGROUND = "migrate-volume-server-partition-background" +COMMAND_MIGRATE_VOLUME_SERVER_PARTITION_STATUS = "migrate-volume-server-partition-status" +COMMAND_REMOVE_SERVER_PARTITION = "remove-server-partition" +COMMAND_REMOVE_VOLUME_USER = "remove-volume-user" +COMMAND_RENAME_VOLUME_USER = "rename-volume-user" +COMMAND_RENAME_VOLUME = "rename-volume" +COMMAND_RUN_SERVER_SERVICE = "run-server-service" +COMMAND_SET_VOLUME_USER_PASSWORD = "set-volume-user-password" +COMMAND_STOP_PARTITION_MIGRATION = "stop-partition-migration" +COMMAND_STOP_VOLUME_SERVER_PARTITION_MIGRATION = "stop-volume-server-partition-migration" +COMMAND_GET_SERVER_DISK_INFO = "get-server-disk-info" +COMMAND_INITIALIZE_SERVER_DISK = "initialize-server-disk" +COMMAND_SET_SERVER_COUNT = "set-server-count" +COMMAND_GET_SERVER_COUNT = "get-server-count" diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Common.py b/src/com.gluster.storage.management.gateway.scripts/src/Common.py new file mode 100644 index 00000000..c85e9a2b --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Common.py @@ -0,0 +1,20 @@ +# Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com>
+# This file is part of GlusterSP.
+#
+# GlusterSP 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.
+#
+# GlusterSP 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 sys
+import syslog
+
diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Disk.py b/src/com.gluster.storage.management.gateway.scripts/src/Disk.py new file mode 100755 index 00000000..2c47d396 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Disk.py @@ -0,0 +1,140 @@ +# Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> +# This file is part of GlusterSP. +# +# GlusterSP 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. +# +# GlusterSP 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 dbus + +class Disk: + def __init__(self): + """init""" + + self.volumes = [] + self.disks = [] + self.bus = dbus.SystemBus() + self.hal_obj = self.bus.get_object("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager") + self.hal = dbus.Interface(self.hal_obj, "org.freedesktop.Hal.Manager") + self.devices = [] + self.devices = self.hal.FindDeviceByCapability("storage") + + self.detect_disks() + self.detect_mountable_volumes() + + def getDiskList(self): + + return self.disks + + def getMountableDiskList(self): + + return self.volumes + + def detect_disks(self): + for device in self.devices: + dev = self._get_device(device) + if dev.GetProperty("storage.drive_type") != "cdrom": + if not dev.GetProperty("block.is_volume"): + self._add_disks(dev) + continue + + def _add_disks(self, dev): + disk = str(dev.GetProperty('block.device')) + disk_size = str(int(dev.GetProperty('storage.size')) / 1024**2) + + try: + if dev.GetProperty('storage.removable'): + disk_size = str(int(dev.GetProperty('storage.removable.media_size')) / 1024**2) + except: + return + + self.disks.append({ + 'device': disk, + 'description': str(dev.GetProperty('storage.model')) + " " + str(dev.GetProperty('storage.vendor')), + 'interface': str(dev.GetProperty('storage.bus')), + 'size': disk_size, + 'drive_type': str(dev.GetProperty('storage.drive_type')) + }) + + def detect_mountable_volumes(self): + """ Detect all mountable volumes using HAL via D-Bus """ + for device in self.devices: + dev = self._get_device(device) + if dev.GetProperty("storage.drive_type") != "cdrom": + if dev.GetProperty("block.is_volume"): + self._add_volume(dev) + continue + else: # iterate over children looking for a volume + children = self.hal.FindDeviceStringMatch("info.parent", + device) + if not children and "disk" == dev.GetProperty("storage.drive_type"): + self._add_volume(dev) + for child in children: + child = self._get_device(child) + if child.GetProperty("block.is_volume"): + self._add_volume(child, parent=dev) + #break # don't break, allow all partitions + + def _add_volume(self, dev, parent=None): + volume = str(dev.GetProperty('block.device')) + if not parent: + self.volumes.append ({ + 'device' : volume, + 'label' : str(dev.GetProperty('block.device')), + 'fstype' : None, + 'fsversion': None, + 'uuid' : None, + 'interface': str(dev.GetProperty('storage.bus')), + 'parent' : None, + 'description': str(dev.GetProperty('storage.model')) + " " + str(dev.GetProperty('storage.vendor')), + 'size' : None, + 'totalsize' : str(int(dev.GetProperty('storage.size')) / 1024**2), + 'drive_type': str(dev.GetProperty('storage.drive_type')), + 'mount_point': "NA" + }) + return + + self.volumes.append ({ + 'device' : volume, + 'label' : str(dev.GetProperty('volume.label')), + 'fstype' : str(dev.GetProperty('volume.fstype')), + 'fsversion': str(dev.GetProperty('volume.fsversion')), + 'uuid' : str(dev.GetProperty('volume.uuid')), + 'interface': str(parent.GetProperty('storage.bus')), + 'parent' : str(parent.GetProperty('block.device')), + 'description': str(parent.GetProperty('storage.model')) + " " + str(parent.GetProperty('storage.vendor')), + 'size' : str(int(dev.GetProperty('volume.size')) / 1024**2), + 'totalsize' : str(int(parent.GetProperty('storage.size')) / 1024**2), + 'drive_type': str(parent.GetProperty('storage.drive_type')), + 'mount_point': str(dev.GetProperty('volume.mount_point')) + }) + return + + def _get_device(self, udi): + """ Return a dbus Interface to a specific HAL device UDI """ + dev_obj = self.bus.get_object("org.freedesktop.Hal", udi) + return dbus.Interface(dev_obj, "org.freedesktop.Hal.Device") + + def get_free_bytes(self, device=None): + """ Return the number of available bytes on our device """ + import statvfs + stat = os.statvfs(device) + return stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL] + + def get_used_bytes(self, device=None): + """ Return the number of used bytes on our device """ + import statvfs + stat = os.statvfs(device) + return ((stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS]) - (stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL])) diff --git a/src/com.gluster.storage.management.gateway.scripts/src/DiskUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/DiskUtils.py new file mode 100644 index 00000000..a0e5d802 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/DiskUtils.py @@ -0,0 +1,939 @@ +# 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 +from copy import deepcopy +import dbus +import Globals +import time +import Utils +import Disk +import Protocol +from FsTabUtils import * + +ONE_MB_SIZE = 1048576 + + +def _stripDev(device): + if Utils.isString(device) and device.startswith("/dev/"): + return device[5:] + return device + + +def _addDev(deviceName): + if Utils.isString(deviceName) and not deviceName.startswith("/dev/"): + return "/dev/" + deviceName + return deviceName + + +def getDeviceName(device): + if type(device) == type([]): + nameList = [] + for d in device: + nameList.append(_stripDev(d)) + return nameList + return _stripDev(device) + + +def getDevice(deviceName): + if Utils.isString(deviceName): + return _addDev(deviceName) + if type(deviceName) == type([]): + nameList = [] + for d in deviceName: + nameList.append(_addDev(d)) + return nameList + return _addDev(deviceName) + + +def getDiskPartitionByUuid(uuid): + uuidFile = "/dev/disk/by-uuid/%s" % uuid + if os.path.exists(uuidFile): + return getDeviceName(os.path.realpath(uuidFile)) + return None + + +def getUuidByDiskPartition(device): + for uuidFile in glob.glob("/dev/disk/by-uuid/*"): + if os.path.realpath(uuidFile) == device: + return os.path.basename(uuidFile) + return None + + +def getDiskPartitionUuid(partition): + Utils.log("WARNING: getDiskPartitionUuid() is deprecated by getUuidByDiskPartition()") + return getUuidByDiskPartition(partition) + + +def getDiskPartitionByLabel(label): + ## TODO: Finding needs to be enhanced + labelFile = "/dev/disk/by-label/%s" % label + if os.path.exists(labelFile): + if os.path.islink(labelFile): + return getDeviceName(os.path.realpath(labelFile)) + return None + + +def getDeviceByLabel(label): + Utils.log("WARNING: getDeviceByLabel() is deprecated by getDiskPartitionByLabel()") + return getDiskPartitionByLabel(label) + + +def getDiskPartitionLabel(device): + rv = Utils.runCommandFG(["sudo", "e2label", device], stdout=True) + if rv["Status"] == 0: + return rv["Stdout"].strip() + return False + + +def readFile(fileName): + lines = None + try: + fp = open(fileName) + lines = fp.readlines() + fp.close() + except IOError, e: + Utils.log("failed to read file %s: %s" % (file, str(e))) + return lines + + +def getRootPartition(fsTabFile=Globals.FSTAB_FILE): + fsTabEntryList = readFsTab(fsTabFile) + for fsTabEntry in fsTabEntryList: + if fsTabEntry["MountPoint"] == "/": + if fsTabEntry["Device"].startswith("UUID="): + return getDiskPartitionByUuid(fsTabEntry["Device"].split("UUID=")[-1]) + if fsTabEntry["Device"].startswith("LABEL="): + partitionName = getDiskPartitionByLabel(fsTabEntry["Device"].split("LABEL=")[-1]) + if partitionName: + return partitionName + return getDeviceName(fsTabEntry["Device"]) + return None + +def getMounts(): + mounts = {} + for line in readFile("/proc/mounts"): + str = line.strip() + if str.startswith("/dev/"): + tokens = str.split() + device = {} + mountPoint = tokens[1].strip() + device["MountPoint"] = mountPoint + device["FsType"] = tokens[2].strip() + device["Uuid"] = getDiskPartitionUuid(tokens[0].strip()) + device["Status"] = "INITIALIZED" + if mountPoint: + if mountPoint in ["/", "/boot"]: + device["Type"] = "BOOT" + else: + device["Type"] = "DATA" + mounts[tokens[0].strip()] = device + return mounts + +def getRaidDisk(): + array = [] + arrayList = [] + mdFound = False + + try: + fp = open("/proc/mdstat") + for line in fp: + str = line.strip() + if str.startswith("md"): + array.append(str) + mdFound = True + continue + if mdFound: + if str: + array.append(str) + else: + arrayList.append(array) + array = [] + mdFound = False + fp.close() + except IOError, e: + return None + + raidList = {} + for array in arrayList: + raid = {} + tokens = array[0].split() + raid['Interface'] = tokens[3] + device = getDevice(tokens[0]) + raid['MountPoint'] = getDeviceMountPoint(device) + if raid['MountPoint']: + raid['Type'] = "DATA" + rv = Utils.runCommand("blkid -c /dev/null %s" % (device), output=True, root=True) + raid['Uuid'] = None + raid['FsType'] = None + raid['Status'] = "UNINITIALIZED" + if isDiskInFormatting(device): + raid['Status'] = "INITIALIZING" + if not rv["Stderr"]: + words = rv["Stdout"].strip().split() + if words: + raid['Status'] = "INITIALIZED" + if len(words) > 2: + raid['Uuid'] = words[1].split("UUID=")[-1].split('"')[1] + raid['FsType'] = words[2].split("TYPE=")[-1].split('"')[1] + + used = 0 + rv = Utils.runCommand("df %s" % (device), output=True, root=True) + if rv["Status"] == 0: + try: + used = long(rv["Stdout"].split("\n")[1].split()[2]) / 1024 + except IndexError: + pass + except ValueError: + pass + raid['SpaceInUse'] = used + raid['Disks'] = [x.split('[')[0] for x in tokens[4:]] + raid['Size'] = float(array[1].split()[0]) / 1024.0 + raidList[tokens[0]] = raid + return raidList + + +def getOsDisk(): + Utils.log("WARNING: getOsDisk() is deprecated by getRootPartition()") + return getRootPartition() + + +def getDiskInfo(diskDeviceList=None): + diskDeviceList = getDevice(diskDeviceList) + if Utils.isString(diskDeviceList): + diskDeviceList = [diskDeviceList] + + mounts = getMounts() + if Utils.runCommand("/usr/bin/lshal") != 0: + Utils.log("failed running /usr/bin/lshal") + + dbusSystemBus = dbus.SystemBus() + halObj = dbusSystemBus.get_object("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager") + halManager = dbus.Interface(halObj, "org.freedesktop.Hal.Manager") + storageUdiList = halManager.FindDeviceByCapability("storage") + + diskInfo = {} + diskList = [] + for udi in storageUdiList: + halDeviceObj = dbusSystemBus.get_object("org.freedesktop.Hal", udi) + halDevice = dbus.Interface(halDeviceObj, + "org.freedesktop.Hal.Device") + if halDevice.GetProperty("storage.drive_type") in ["cdrom", "floppy"] or \ + halDevice.GetProperty("block.is_volume"): + continue + disk = {} + disk["Device"] = str(halDevice.GetProperty('block.device')) + if diskDeviceList and disk["Device"] not in diskDeviceList: + continue + disk["Description"] = str(halDevice.GetProperty('storage.vendor')) + " " + str(halDevice.GetProperty('storage.model')) + if halDevice.GetProperty('storage.removable'): + disk["Size"] = long(halDevice.GetProperty('storage.removable.media_size')) + else: + disk["Size"] = long(halDevice.GetProperty('storage.size')) / 1024**2 + disk["Interface"] = str(halDevice.GetProperty('storage.bus')) + disk["DriveType"] = str(halDevice.GetProperty('storage.drive_type')) + disk["Status"] = None + disk["Uuid"] = None + disk["Init"] = False + disk["Type"] = None + disk["FsType"] = None + disk["FsVersion"] = None + disk["MountPoint"] = None + disk["ReadOnlyAccess"] = None + disk["SpaceInUse"] = None + + partitionUdiList = halManager.FindDeviceStringMatch("info.parent", udi) + if isDiskInFormatting(disk["Device"]): + disk["Status"] = "INITIALIZING" + else: + if partitionUdiList: + disk["Status"] = "INITIALIZED" + else: + disk["Status"] = "UNINITIALIZED" + disk["Type"] = "UNKNOWN" + + if mounts and mounts.has_key(disk["Device"]): + disk["Uuid"] = mounts[disk["Device"]]["Uuid"] + disk["Type"] = mounts[disk["Device"]]["Type"] + disk["Status"] = mounts[disk["Device"]]["Status"] + disk["FsType"] = mounts[disk["Device"]]["FsType"] + disk["MountPoint"] = mounts[disk["Device"]]["MountPoint"] + + partitionList = [] + diskSpaceInUse = 0 + for partitionUdi in partitionUdiList: + used = 0 + partitionHalDeviceObj = dbusSystemBus.get_object("org.freedesktop.Hal", + partitionUdi) + partitionHalDevice = dbus.Interface(partitionHalDeviceObj, + "org.freedesktop.Hal.Device") + if not partitionHalDevice.GetProperty("block.is_volume"): + continue + partitionDevice = str(partitionHalDevice.GetProperty('block.device')) + if partitionHalDevice.GetProperty("volume.is_mounted"): + rv = Utils.runCommandFG(["df", str(partitionHalDevice.GetProperty('volume.mount_point'))], stdout=True) + if rv["Status"] == 0: + try: + used = long(rv["Stdout"].split("\n")[1].split()[2]) / 1024 + diskSpaceInUse += used + except IndexError: + pass + except ValueError: + pass + + if disk["Device"] == partitionDevice: + disk["Uuid"] = str(partitionHalDevice.GetProperty('volume.uuid')) + disk["Init"] = True # TODO: use isDataDiskPartitionFormatted function to cross verify this + disk["Status"] = "INITIALIZED" + mountPoint = str(partitionHalDevice.GetProperty('volume.mount_point')) + if mountPoint: + if mountPoint in ["/", "/boot"]: + disk["Type"] = "BOOT" + else: + disk["Type"] = "DATA" + disk["FsType"] = str(partitionHalDevice.GetProperty('volume.fstype')) + if disk["FsType"] and "UNINITIALIZED" == disk["Status"]: + disk["Status"] = "INITIALIZED" + disk["FsVersion"] = str(partitionHalDevice.GetProperty('volume.fsversion')) + disk["MountPoint"] = str(partitionHalDevice.GetProperty('volume.mount_point')) + disk["ReadOnlyAccess"] = str(partitionHalDevice.GetProperty('volume.is_mounted_read_only')) + if not disk["Size"]: + disk["Size"] = long(partitionHalDevice.GetProperty('volume.size')) / 1024**2 + disk["SpaceInUse"] = used + continue + + partition = {} + partition["Init"] = False + partition["Type"] = "UNKNOWN" + partition["Device"] = partitionDevice + partition["Uuid"] = str(partitionHalDevice.GetProperty('volume.uuid')) + partition["Size"] = long(partitionHalDevice.GetProperty('volume.size')) / 1024**2 + partition["FsType"] = str(partitionHalDevice.GetProperty('volume.fstype')) + partition["FsVersion"] = str(partitionHalDevice.GetProperty('volume.fsversion')) + partition["Label"] = str(partitionHalDevice.GetProperty('volume.label')) + partition["MountPoint"] = str(partitionHalDevice.GetProperty('volume.mount_point')) + partition["Size"] = long(partitionHalDevice.GetProperty('volume.size')) / 1024**2 + + if isDiskInFormatting(partitionDevice): + partition["Status"] = "INITIALIZING" + else: + if partition["FsType"]: + partition["Status"] = "INITIALIZED" + else: + partition["Status"] = "UNINITIALIZED" + + partition["SpaceInUse"] = used + if partition["MountPoint"] or isDataDiskPartitionFormatted(partitionDevice): + partition["Init"] = True + partition["Status"] = "INITIALIZED" + if partition["MountPoint"]: + if partition["MountPoint"] in ["/", "/boot"]: + partition["Type"] = "BOOT" + else: + partition["Type"] = "DATA" + else: + if "SWAP" == partition["FsType"].strip().upper(): + partition["Type"] = "SWAP" + partition["ReadOnlyAccess"] = str(partitionHalDevice.GetProperty('volume.is_mounted_read_only')) + partitionList.append(partition) + disk["Partitions"] = partitionList + if not disk["SpaceInUse"]: + disk["SpaceInUse"] = diskSpaceInUse + diskList.append(disk) + diskInfo["disks"] = diskList + if diskList: + return diskInfo + for line in readFile("/proc/partitions")[2:]: + disk = {} + tokens = line.split() + if tokens[3].startswith("md"): + continue + disk["Device"] = tokens[3] + ## if diskDeviceList and disk["Device"] not in diskDeviceList: + ## continue + disk["Description"] = None + disk["Size"] = long(tokens[2]) / 1024 + disk["Status"] = None + disk["Interface"] = None + disk["DriveType"] = None + disk["Uuid"] = None + disk["Init"] = False + disk["Type"] = None + disk["FsType"] = None + disk["FsVersion"] = None + disk["MountPoint"] = None + disk["ReadOnlyAccess"] = None + disk["SpaceInUse"] = None + disk["Partitions"] = [] + diskList.append(disk) + diskInfo["disks"] = diskList + return diskInfo + +def getDiskList(diskDeviceList=None): + return diskInfo["disks"] + +def readFsTab(fsTabFile=Globals.FSTAB_FILE): + try: + fsTabfp = open(fsTabFile) + except IOError, e: + Utils.log("readFsTab(): " + str(e)) + return None + + fsTabEntryList = [] + for line in fsTabfp: + tokens = line.strip().split() + if not tokens or tokens[0].startswith('#'): + continue + fsTabEntry = {} + fsTabEntry["Device"] = None + fsTabEntry["MountPoint"] = None + fsTabEntry["FsType"] = None + fsTabEntry["Options"] = None + fsTabEntry["DumpOption"] = 0 + fsTabEntry["fsckOrder"] = 0 + try: + fsTabEntry["Device"] = tokens[0] + fsTabEntry["MountPoint"] = tokens[1] + fsTabEntry["FsType"] = tokens[2] + fsTabEntry["Options"] = tokens[3] + fsTabEntry["DumpOption"] = tokens[4] + fsTabEntry["fsckOrder"] = tokens[5] + except IndexError: + pass + if fsTabEntry["Device"] and fsTabEntry["MountPoint"] and fsTabEntry["FsType"] and fsTabEntry["Options"]: + fsTabEntryList.append(fsTabEntry) + fsTabfp.close() + return fsTabEntryList + + +def checkDiskMountPoint(diskMountPoint): + try: + fstabEntries = open(Globals.FSTAB_FILE).readlines() + except IOError: + fstabEntries = [] + found = False + for entry in fstabEntries: + entry = entry.strip() + if not entry: + continue + entries = entry.split() + if entries and len(entries) > 1 and entries[0].startswith("UUID=") and entries[1].upper() == diskMountPoint.upper(): + return True + return False + + +def getMountPointByUuid(partitionUuid): + # check uuid in etc/fstab + try: + fstabEntries = open(Globals.FSTAB_FILE).readlines() + except IOError: + fstabEntries = [] + found = False + for entry in fstabEntries: + entry = entry.strip() + if not entry: + continue + if entry.split()[0] == "UUID=" + partitionUuid: + return entry.split()[1] + return None + + +def getDiskSizeInfo(partition): + # get values from df output + total = None + used = None + free = None + command = "df -kl -t ext3 -t ext4 -t xfs" + rv = Utils.runCommandFG(command, stdout=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + Utils.log("failed to get disk details. %s" % Utils.stripEmptyLines(rv["Stdout"])) + return None, None, None + for line in rv["Stdout"].split("\n"): + tokens = line.split() + if len(tokens) < 4: + continue + if tokens[0] == partition: + total = int(tokens[1]) / 1024.0 + used = int(tokens[2]) / 1024.0 + free = int(tokens[3]) / 1024.0 + break + + if total: + return total, used, free + + # get total size from parted output + for i in range(len(partition), 0, -1): + pos = i - 1 + if not partition[pos].isdigit(): + break + disk = partition[:pos+1] + partitionNumber = partition[pos+1:] + if not partitionNumber.isdigit(): + return None, None, None + + number = int(partitionNumber) + command = "parted -ms %s unit kb print" % disk + rv = Utils.runCommandFG(command, stdout=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + Utils.log("failed to get disk details. %s" % Utils.stripEmptyLines(rv["Stdout"])) + return None, None, None + + lines = rv["Stdout"].split(";\n") + if len(lines) < 3: + return None,None,None + + for line in lines[2:]: + tokens = line.split(':') + if len(tokens) < 4: + continue + if tokens[0] == str(number): + total = int(tokens[3].split('kB')[0]) / 1024.0 + break + return total, used, free + + +def isDataDiskPartitionFormatted(device): + #Todo: Proper label needs to be added for data partition + #if getDiskPartitionLabel(device) != Globals.DATA_PARTITION_LABEL: + # return False + device = getDeviceName(device) + diskObj = Disk.Disk() + for disk in diskObj.getMountableDiskList(): + if disk['device'].upper() == device.upper(): + mountPoint = disk['mount_point'] + if not mountPoint: + return False + if not os.path.exists(mountPoint): + return False + + uuid = getUuidByDiskPartition(device) + if not uuid: + return False + + for fsTabEntry in readFsTab(): + if fsTabEntry["Device"] == ("UUID=%s" % uuid) and fsTabEntry["MountPoint"] == mountPoint: + return True + return False + + +def getDiskDom(diskDeviceList=None, bootPartition=None, skipDisk=None): + diskDeviceList = getDevice(diskDeviceList) + if Utils.isString(diskDeviceList): + diskDeviceList = [diskDeviceList] + + if skipDisk: + skipDisk = getDevice(skipDisk) + if Utils.isString(skipDisk): + skipDisk = [skipDisk] + + diskInfo = getDiskInfo(diskDeviceList) + diskList = diskInfo["disks"] + if not diskList: + return None + + raidPartitions = {} + raidDisk = getRaidDisk() + + for k, v in raidDisk.iteritems(): + for i in v['Disks']: + raidPartitions[i] = k + + #for partition in raidDisk.values(): + # raidDiskPartitions += partition['disks'] + + diskDom = Protocol.XDOM() + disksTag = diskDom.createTag("disks", None) + raidDisks = {} + if not bootPartition: + bootPartition = getRootPartition() + for disk in diskList: + if skipDisk and disk["Device"] in skipDisk: + continue + diskTag = diskDom.createTag("disk", None) + diskDevice = getDeviceName(disk["Device"]) + diskTag.appendChild(diskDom.createTag("name", diskDevice)) + diskTag.appendChild(diskDom.createTag("description", disk["Description"])) + diskTag.appendChild(diskDom.createTag("uuid", disk["Uuid"])) + diskTag.appendChild(diskDom.createTag("status", disk["Status"])) + diskTag.appendChild(diskDom.createTag("interface", disk["Interface"])) + + #if not disk["Partitions"]: + diskTag.appendChild(diskDom.createTag("type", disk["Type"])) + #diskTag.appendChild(diskDom.createTag("init", str(disk["Init"]).lower())) + diskTag.appendChild(diskDom.createTag("fsType", disk["FsType"])) + diskTag.appendChild(diskDom.createTag("fsVersion", disk["FsVersion"])) + diskTag.appendChild(diskDom.createTag("mountPoint", disk["MountPoint"])) + + diskTag.appendChild(diskDom.createTag("size", disk["Size"])) + diskTag.appendChild(diskDom.createTag("spaceInUse", disk["SpaceInUse"])) + partitionsTag = diskDom.createTag("partitions", None) + if raidPartitions.has_key(diskDevice): + rdList = {} + rdList[diskDevice] = [deepcopy(diskTag)] + if not raidDisks.has_key(raidPartitions[diskDevice]): + raidDisks[raidPartitions[diskDevice]] = [] + raidDisks[raidPartitions[diskDevice]] += [rdList] + continue + for partition in disk["Partitions"]: + partitionTag = diskDom.createTag("partition", None) + device = getDeviceName(partition["Device"]) + partitionTag.appendChild(diskDom.createTag("name", device)) + if partition["Uuid"]: #TODO: Move this verification and findings to getDiskInfo function + partitionTag.appendChild(diskDom.createTag("uuid", partition["Uuid"])) + else: + partitionTag.appendChild(diskDom.createTag("uuid", getUuidByDiskPartition("/dev/" + device))) + partitionTag.appendChild(diskDom.createTag("status", partition["Status"])) + #partitionTag.appendChild(diskDom.createTag("init", str(partition["Init"]).lower())) + partitionTag.appendChild(diskDom.createTag("type", str(partition["Type"]))) + partitionTag.appendChild(diskDom.createTag("fsType", partition["FsType"])) + partitionTag.appendChild(diskDom.createTag("mountPoint", partition['MountPoint'])) + partitionTag.appendChild(diskDom.createTag("size", partition["Size"])) + partitionTag.appendChild(diskDom.createTag("spaceInUse", partition["SpaceInUse"])) + if raidPartitions.has_key(device): + tempPartitionTag = diskDom.createTag("partitions", None) + if raidDisks.has_key(raidPartitions[device]): + rdList = raidDisks[raidPartitions[device]] + for rdItem in rdList: + if not rdItem.has_key(diskDevice): + rdItem[diskDevice] = [deepcopy(diskTag), tempPartitionTag] + rdItem[diskDevice][0].appendChild(tempPartitionTag) + rdItem[diskDevice][-1].appendChild(partitionTag) + continue + rdList = {} + rdList[diskDevice] = [deepcopy(diskTag), tempPartitionTag] + tempPartitionTag.appendChild(partitionTag) + rdList[diskDevice][0].appendChild(tempPartitionTag) + raidDisks[raidPartitions[device]] = [rdList] + continue + partitionsTag.appendChild(partitionTag) + diskTag.appendChild(partitionsTag) + disksTag.appendChild(diskTag) + + for rdisk in raidDisk.keys(): + raidDiskTag = diskDom.createTag("disk", None) + raidDiskTag.appendChild(diskDom.createTag("name", rdisk)) + raidDiskTag.appendChild(diskDom.createTag("description")) + raidDiskTag.appendChild(diskDom.createTag("uuid", raidDisk[rdisk]['Uuid'])) + raidDiskTag.appendChild(diskDom.createTag("type", raidDisk[rdisk]['Type'])) + raidDiskTag.appendChild(diskDom.createTag("mountPoint", raidDisk[rdisk]['MountPoint'])) + raidDiskTag.appendChild(diskDom.createTag("status", raidDisk[rdisk]['Status'])) + raidDiskTag.appendChild(diskDom.createTag("interface", raidDisk[rdisk]['Interface'])) + raidDiskTag.appendChild(diskDom.createTag("fsType", raidDisk[rdisk]['FsType'])) + raidDiskTag.appendChild(diskDom.createTag("fsVersion")) + raidDiskTag.appendChild(diskDom.createTag("size", raidDisk[rdisk]['Size'])) + raidDiskTag.appendChild(diskDom.createTag("spaceInUse", raidDisk[rdisk]['SpaceInUse'])) + raidDisksTag = diskDom.createTag("raidDisks", None) + if raidDisks.has_key(rdisk): + for item in raidDisks[rdisk]: + for diskTag in item.values(): + raidDisksTag.appendChild(diskTag[0]) + raidDiskTag.appendChild(raidDisksTag) + disksTag.appendChild(raidDiskTag) + diskDom.addTag(disksTag) + return diskDom + + +def initializeDisk(disk, boot=False, startSize=0, sudo=False): + if boot and startSize > 0: + return False + + disk = getDevice(disk) + diskObj = getDiskList(disk)[0] + + if boot or startSize == 0: + command = "dd if=/dev/zero of=%s bs=1024K count=1" % diskObj["Device"] + if runCommandFG(command, root=sudo) != 0: + if boot: + Utils.log("failed to clear boot sector of disk %s" % diskObj["Device"]) + return False + Utils.log("failed to clear boot sector of disk %s. ignoring" % diskObj["Device"]) + + command = "parted -s %s mklabel gpt" % diskObj["Device"] + if runCommandFG(command, root=sudo) != 0: + return False + + if boot: + command = "parted -s %s mkpart primary ext3 0MB %sMB" % (diskObj["Device"], Globals.OS_PARTITION_SIZE) + if runCommandFG(command, root=sudo) != 0: + return False + command = "parted -s %s set 1 boot on" % (diskObj["Device"]) + if runCommandFG(command, root=sudo) != 0: + return False + startSize = Globals.OS_PARTITION_SIZE + + size = (diskObj["Size"] / ONE_MB_SIZE) - startSize + while size > Globals.MAX_PARTITION_SIZE: + endSize = startSize + Globals.MAX_PARTITION_SIZE + command = "parted -s %s mkpart primary ext3 %sMB %sMB" % (diskObj["Device"], startSize, endSize) + if runCommandFG(command, root=sudo) != 0: + return False + size -= Globals.MAX_PARTITION_SIZE + startSize = endSize + + if size: + command = "parted -s %s mkpart primary ext3 %sMB 100%%" % (diskObj["Device"], startSize) + if runCommandFG(command, root=sudo) != 0: + return False + + if runCommandFG("udevadm settle", root=sudo) != 0: + if runCommandFG("udevadm settle", root=sudo) != 0: + Utils.log("udevadm settle for disk %s failed. ignoring" % diskObj["Device"]) + time.sleep(1) + + if runCommandFG("partprobe %s" % diskObj["Device"], root=sudo) != 0: + Utils.log("partprobe %s failed" % diskObj["Device"]) + return False + + if runCommandFG("gptsync %s" % diskObj["Device"], root=sudo) != 0: + Utils.log("gptsync %s failed. ignoring" % diskObj["Device"]) + + # wait forcefully to appear devices in /dev + time.sleep(2) + return True + + +def initializeOsDisk(diskObj): + Utils.log("WARNING: initializeOsDisk() is deprecated by initializeDisk(boot=True)") + return initializeDisk(diskObj, boot=True) + + +def initializeDataDisk(diskObj): + Utils.log("WARNING: initializeDataDisk() is deprecated by initializeDisk()") + return initializeDisk(diskObj) + +def getBootPartition(serverName): + diskDom = XDOM() + diskDom.parseFile("%s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + if not diskDom: + return None + partitionDom = XDOM() + partitionUuid = None + partitionName = None + for partitionTag in diskDom.getElementsByTagRoute("disk.partition"): + partitionDom.setDomObj(partitionTag) + boot = partitionDom.getTextByTagRoute("boot") + if boot and boot.strip().upper() == 'YES': + partitionUuid = partitionDom.getTextByTagRoute("uuid") + partitionName = partitionDom.getTextByTagRoute("device") + break + if not (partitionUuid and partitionName): + return None + + # check device label name + deviceBaseName = os.path.basename(partitionName) + process = runCommandBG(['sudo', 'e2label', partitionName]) + if type(process) == type(True): + return None + if process.wait() != 0: + return None + output = process.communicate() + deviceLabel = output[0].split()[0] + if deviceLabel != Globals.BOOT_PARTITION_LABEL: + return None + + # check uuid in etc/fstab + try: + fstabEntries = open(Globals.FSTAB_FILE).readlines() + except IOError: + fstabEntries = [] + found = False + for entry in fstabEntries: + entry = entry.strip() + if not entry: + continue + if entry.split()[0] == "UUID=" + partitionUuid: + found = True + break + if not found: + return None + return partitionName + + +def isDiskInFormatting(device): + DEVICE_FORMAT_LOCK_FILE = "/var/lock/%s.lock" % device + return os.path.exists(DEVICE_FORMAT_LOCK_FILE) + + +def isDiskInFormat(device): + Utils.log("WARNING: isDiskInFormat() is deprecated by isDataDiskPartitionFormatted()") + return isDataDiskPartitionFormatted(device) + + +def diskOrder(serverExportList): + newServerExportList = [] + while serverExportList: + serverExport = deepcopy(serverExportList[0]) + if newServerExportList and serverExport.split(":")[0] == newServerExportList[-1].split(":")[0]: + inserted = False + for i in range(0, len(newServerExportList) - 1): + if serverExport.split(":")[0] == newServerExportList[i].split(":")[0]: + continue + if i == 0: + newServerExportList.insert(i, serverExport) + inserted = True + break + if serverExport.split(":")[0] == newServerExportList[i - 1].split(":")[0]: + continue + newServerExportList.insert(i, serverExport) + inserted = True + break + if not inserted: + newServerExportList.append(serverExport) + else: + newServerExportList.append(serverExport) + serverExportList.remove(serverExport) + i = 0 + while serverExportList and i < len(serverExportList): + if serverExport.split(":")[0] == serverExportList[i].split(":")[0]: + i += 1 + continue + serverExport = deepcopy(serverExportList[i]) + newServerExportList.append(serverExport) + serverExportList.remove(serverExport) + return newServerExportList + + +def updateServerDiskConfig(serverName, diskDom, requestFlag=True, partitionFlag=True): + command = "command.server." + if not requestFlag: + command = "" + diskList = {} + for tagE in diskDom.getElementsByTagRoute(command + "disk"): + diskList[diskDom.getTextByTagRoute(command + "device")] = tagE + configDom = XDOM() + if not configDom.parseFile("%s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)): + return diskDom.writexml("%s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + diskTag = configDom.getElementsByTagRoute("disks.disk") + disks = configDom.getElementsByTagRoute("disks") + if not (diskTag or disks): + return None + for tagE in diskTag: + diskDom = XDOM() + diskDom.setDomObj(tagE) + device = diskDom.getTextByTagRoute("device") + if partitionFlag and device in diskList: + disks[0].removeChild(tagE) + disks[0].appendChild(deepcopy(diskList[device])) + continue + if not partitionFlag and device in diskList: + partitionList = [] + for childNodeTag in tagE.childNodes: + if childNodeTag.nodeName == 'partition': + partitionList.append(childNodeTag) + tagE.childNodes = [] + tagE.childNodes = diskList[device].childNodes + partitionList + return configDom.writexml("%s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + + +def compareDisksDom(diskDomA, diskDomB, requestFlag=True): + command = "command.server.disk." + if not requestFlag: + command = "" + sourceDiskList = {} + sourceDisk = {} + for tagE in diskDomA.getElementsByTagRoute("disk"): + sourceDisk["description"] = diskDomA.getTextByTagRoute("description") + sourceDisk["size"] = diskDomA.getTextByTagRoute("size") + sourceDisk["init"] = diskDomA.getTextByTagRoute("init") + sourceDisk["interface"] = diskDomA.getTextByTagRoute("interface") + sourceDiskList[diskDomA.getTextByTagRoute("device")] = sourceDisk + objDiskList = {} + objDisk = {} + for tagE in diskDomB.getElementsByTagRoute("disk"): + objDisk["description"] = diskDomB.getTextByTagRoute("description") + objDisk["size"] = diskDomB.getTextByTagRoute("size") + objDisk["init"] = diskDomB.getTextByTagRoute("init") + objDisk["interface"] = diskDomB.getTextByTagRoute("interface") + objDiskList[diskDomB.getTextByTagRoute("device")] = objDisk + return sourceDiskList == objDiskList + + +def compareDiskDom(diskDomA, diskDomB, requestFlag=True): + command = "command.server.disk." + if not requestFlag: + command = "" + sourceDisk = {} + sourceDisk["device"] = diskDomA.getTextByTagRoute("device") + sourceDisk["description"] = diskDomA.getTextByTagRoute("description") + sourceDisk["size"] = diskDomA.getTextByTagRoute("size") + sourceDisk["init"] = diskDomA.getTextByTagRoute("init") + sourceDisk["interface"] = diskDomA.getTextByTagRoute("interface") + for tagE in diskDomA.getElementsByTagRoute("partition"): + sourceDiskPartitions = {} + partitionDom = XDOM() + partitionDom.setDomObj(tagE) + sourceDiskPartitions["size"] = partitionDom.getTextByTagRoute("size") + #sourceDiskPartitions["free"] = partitionDom.getTextByTagRoute("free") + sourceDiskPartitions["format"] = partitionDom.getTextByTagRoute("format") + sourceDiskPartitions["uuid"] = partitionDom.getTextByTagRoute("uuid") + sourceDisk[partitionDom.getTextByTagRoute("device")] = sourceDiskPartitions + + objDisk = {} + objDisk["device"] = diskDomB.getTextByTagRoute(command + "device") + objDisk["description"] = diskDomB.getTextByTagRoute(command + "description") + objDisk["size"] = diskDomB.getTextByTagRoute(command + "size") + objDisk["init"] = diskDomB.getTextByTagRoute(command + "init") + objDisk["interface"] = diskDomB.getTextByTagRoute(command + "interface") + for tagE in diskDomB.getElementsByTagRoute(command + "partition"): + objDiskPartitions = {} + partitionDom = XDOM() + partitionDom.setDomObj(tagE) + objDiskPartitions["size"] = partitionDom.getTextByTagRoute("size") + #objDiskPartitions["free"] = partitionDom.getTextByTagRoute("free") + objDiskPartitions["format"] = partitionDom.getTextByTagRoute("format") + objDiskPartitions["uuid"] = partitionDom.getTextByTagRoute("uuid") + objDisk[partitionDom.getTextByTagRoute("device")] = objDiskPartitions + return sourceDisk == objDisk + + +def getServerConfigDiskDom(serverName, diskName=None): + diskConfigDom = XDOM() + if not diskConfigDom.parseFile("%s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)): + Utils.log("Unable to parse %s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + return None + diskTag = diskConfigDom.getElementsByTagRoute("disks.disk") + if not diskTag: + Utils.log("Unable to reterive disk information %s/%s/disk.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + return None + if diskName: + for tagE in diskTag: + diskDom = XDOM() + diskDom.setDomObj(tagE) + if diskName == diskDom.getTextByTagRoute("device"): + return diskDom + return None + + for tagE in diskTag: + for partitionTag in tagE.getElementsByTagName("partition"): + tagE.removeChild(partitionTag) + return diskConfigDom + + +def getDeviceMountPoint(device): + try: + fp = open("/proc/mounts") + for token in [line.strip().split() for line in fp.readlines()]: + if token and len(token) > 2 and token[0] == device: + return token[1] + fp.close() + except IOError, e: + return None + diff --git a/src/com.gluster.storage.management.gateway.scripts/src/FsTabUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/FsTabUtils.py new file mode 100644 index 00000000..fcac4196 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/FsTabUtils.py @@ -0,0 +1,92 @@ +# 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 Globals + +def readFsTab(fsTabFile=Globals.FSTAB_FILE): + try: + fsTabfp = open(fsTabFile) + except IOError, e: + log("readFsTab(): " + str(e)) + return None + + fsTabEntryList = [] + for line in fsTabfp: + tokens = line.strip().split() + if not tokens or tokens[0].startswith('#'): + continue + fsTabEntry = {} + fsTabEntry["Device"] = None + fsTabEntry["MountPoint"] = None + fsTabEntry["FsType"] = None + fsTabEntry["Options"] = None + fsTabEntry["DumpOption"] = 0 + fsTabEntry["fsckOrder"] = 0 + try: + fsTabEntry["Device"] = tokens[0] + fsTabEntry["MountPoint"] = tokens[1] + fsTabEntry["FsType"] = tokens[2] + fsTabEntry["Options"] = tokens[3] + fsTabEntry["DumpOption"] = tokens[4] + fsTabEntry["fsckOrder"] = tokens[5] + except IndexError: + pass + if fsTabEntry["Device"] and fsTabEntry["MountPoint"] and fsTabEntry["FsType"] and fsTabEntry["Options"]: + fsTabEntryList.append(fsTabEntry) + + fsTabfp.close() + return fsTabEntryList + +def writeFsTab(fsTabEntryList, fsTabFile=Globals.FSTAB_FILE): + try: + fsTabfp = open(fsTabFile, "w") + for fsTabEntry in fsTabEntryList: + fsTabfp.write("%s\t%s\t%s\t%s\t%s\t%s\n" % + (fsTabEntry["Device"], fsTabEntry["MountPoint"], + fsTabEntry["FsType"], fsTabEntry["Options"], + fsTabEntry["DumpOption"], fsTabEntry["fsckOrder"])) + fsTabfp.close() + except IOError, e: + log("writeFsTab(): " + str(e)) + return False + return True + +def addFsTabEntry(fsTabEntry, fsTabFile=Globals.FSTAB_FILE): + try: + fsTabfp = open(fsTabFile, "a") + fsTabfp.write("%s\t%s\t%s\t%s\t%s\t%s\n" % + (fsTabEntry["Device"], fsTabEntry["MountPoint"], + fsTabEntry["FsType"], fsTabEntry["Options"], + fsTabEntry["DumpOption"], fsTabEntry["fsckOrder"])) + fsTabfp.close() + except IOError, e: + log("addFsTabEntry(): " + str(e)) + return False + return True + +def removeFsTabEntry(fsTabEntry, fsTabFile=Globals.FSTAB_FILE): + fsTabEntryList = readFsTab(fsTabFile) + if not fsTabEntryList: + return False + + try: + fsTabEntryList.remove(fsTabEntry) + except ValueError: + return False + + return writeFsTab(fsTabEntryList, fsTabFile) + diff --git a/src/com.gluster.storage.management.gateway.scripts/src/GetServerNetworkConfig.py b/src/com.gluster.storage.management.gateway.scripts/src/GetServerNetworkConfig.py new file mode 100644 index 00000000..3311eb56 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/GetServerNetworkConfig.py @@ -0,0 +1,96 @@ +# Copyright (C) 2009 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 sys +import syslog +import Globals +import Commands +import re +from ServerUtils import * +from Protocol import * +from NetworkUtils import * + +def getServerNetworkConfig(requestXml): + serverName = requestXml.getTextByTagRoute("command.server-name") + version = requestXml.getVersion() + messageId = requestXml.getAttribute("id") + + if not serverName: + responseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG, "No server name given", messageId, version) + responseDom.appendTagRoute("server.name", serverName) + return responseDom + responseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG, "OK", messageId, version) + serverTag = responseDom.createTag("server", None) + serverTag.appendChild(responseDom.createTag("name", serverName)) + nameServerList, domain, searchDomain = readResolvConfFile() + if domain: + domainName = domain[0] + else: + domainName = None + serverTag.appendChild(responseDom.createTag("domainname", domainName)) + i = 1 + for dns in nameServerList: + serverTag.appendChild(responseDom.createTag("dns%s" % i, dns)) + i += 1 + #TODO: probe and retrieve timezone, ntp-server, preferred-network details and update the tags + configDom = XDOM() + if configDom.parseFile("%s/%s/network.xml" % (Globals.SERVER_CONF_DIR, serverName)): + serverTag.appendChild(responseDom.createTag("timezone", configDom.getTextByTagRoute("network.timezone"))) + serverTag.appendChild(responseDom.createTag("ntp-server", configDom.getTextByTagRoute("network.ntp-server"))) + preferredNetwork = configDom.getTextByTagRoute("network.preferred-network") + if not preferredNetwork: + preferredNetwork = "any" + serverTag.appendChild(responseDom.createTag("preferred-network", preferredNetwork)) + + deviceList = {} + for device in getNetDeviceList(): + deviceList[device["device"]] = device + try: + macAddress = open("/sys/class/net/%s/address" % device["device"]).read().strip() + except IOError: + continue + interfaceTag = responseDom.createTag("interface", None) + interfaceTag.appendChild(responseDom.createTag("device", device["device"])) + interfaceTag.appendChild(responseDom.createTag("description", device["description"])) + interfaceTag.appendChild(responseDom.createTag("hwaddr", macAddress)) + if deviceList[device["device"]]: + if deviceList[device["device"]]["onboot"]: + interfaceTag.appendChild(responseDom.createTag("onboot", "yes")) + else: + interfaceTag.appendChild(responseDom.createTag("onboot", "no")) + interfaceTag.appendChild(responseDom.createTag("bootproto", deviceList[device["device"]]["bootproto"])) + interfaceTag.appendChild(responseDom.createTag("ipaddr", deviceList[device["device"]]["ipaddr"])) + interfaceTag.appendChild(responseDom.createTag("netmask", deviceList[device["device"]]["netmask"])) + interfaceTag.appendChild(responseDom.createTag("gateway", deviceList[device["device"]]["gateway"])) + if deviceList[device["device"]]["mode"]: + interfaceTag.appendChild(responseDom.createTag("mode", deviceList[device["device"]]["mode"])) + if deviceList[device["device"]]["master"]: + interfaceTag.appendChild(responseDom.createTag("bonding", "yes")) + spliter = re.compile(r'[\D]') + interfaceTag.appendChild(responseDom.createTag("bondid", spliter.split(device["master"])[-1])) + else: + interfaceTag.appendChild(responseDom.createTag("onboot", "no")) + interfaceTag.appendChild(responseDom.createTag("bootproto", "none")) + serverTag.appendChild(interfaceTag) + responseDom.appendTag(serverTag) + return responseDom + +def test(): + requestString = """<command request="get-server-network-config" id="123" version="3.1.2.2"> +<server-name>s1</server-name></command>""" + requestDom = RequestXml(requestString) + print getServerNetworkConfig(requestDom).toxml() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Globals.py b/src/com.gluster.storage.management.gateway.scripts/src/Globals.py new file mode 100644 index 00000000..f8a07c25 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Globals.py @@ -0,0 +1,123 @@ +# 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/>. + +MULTICAST_GROUP = '224.224.1.1' +MULTICAST_PORT = 5353 +GLUSTER_PLATFORM_VERSION = "3.2" + +## System configuration constants +SYSCONFIG_NETWORK_DIR = "/etc/sysconfig/network-scripts" +DNSMASQ_CONF_DIR = "/etc/dnsmasq.d" + +FSTAB_FILE = "/etc/fstab" +NFS_EXPORTS_FILE = "/etc/exports" +SAMBA_CONF_FILE = "/etc/samba/smb.conf" +TIMEZONE_FILE = "/etc/timezone" +ZONEINFO_DIR = "/usr/share/zoneinfo" +LOCALTIME_FILE = "/etc/localtime" +KERBEROS_CONF_FILE = "/etc/krb5.conf" +NSSWITCH_CONF_FILE = "/etc/nsswitch.conf" +NTP_CONF_FILE = "/etc/ntp.conf" +MODPROBE_CONF_FILE = "/etc/modprobe.d/bonding.conf" +SYSCONFIG_NETWORK_FILE = "/etc/sysconfig/network" +RESOLV_CONF_FILE = "/etc/resolv.conf" +DNSMASQ_LEASE_FILE = "/var/tmp/dnsmasq.leases" +LIVE_MODE_FILE = "/etc/live" +ADD_SERVER_COMPLETED_FILE = "/var/tmp/installation-completed" + +DNSMASQ_DNS_CONF_FILE = DNSMASQ_CONF_DIR + "/dns.conf" +DNSMASQ_DHCP_CONF_FILE = DNSMASQ_CONF_DIR + "/dhcp.conf" +## + +## Base constants +MAX_PARTITION_SIZE = 16777216 # 16 TB +OS_PARTITION_SIZE = 4000 # 4 GB +SESSION_TIMEOUT = 1800 # 30 minutes +SERVER_AGENT_PORT = 50000 + +BOOT_PARTITION_LABEL = "GLUSTEROS" +DATA_PARTITION_LABEL = "GLUSTERDATA" +VOLUME_USER_DESCRIPTION = "Gluster Volume User" +SERVER_AGENT_RUN_USERNAME = "gluster" +INSTALLER_SERVER_NAME = "$installer$" + +GLUSTER_BASE_DIR = "/etc/glustermg" +GLUSTER_LUN_DIR = "/data" +REEXPORT_DIR = "/reexport" +NFS_EXPORT_DIR = "/nfs" +CIFS_EXPORT_DIR = "/cifs" +WEBDAV_DOCUMENT_ROOT_DIR = "/var/www/html" +UPDATES_DIR = "/UPDATES" +TRANSPORT_HOME_DIR = "/transport" +GLUSTERFS_LOG_DIR = "/var/log/glusterfs" +LOG_DIR = "/var/log/glustermg" + +GLUSTER_UPDATES_FILE = "updates.xml" +INSTALLER_STATUS_FILE = "/var/log/install-server-status.log" +INSTALL_PLATFORM_LOCK_FILE = "/var/lock/install-gluster-platform.lock" +LAST_ACCESSED_NETWORK_FILE = "last-accessed-network" +PREPARE_DATA_DISK_LOCK_FILE = "/var/tmp/prepare-data-disk.lock" +## + +## Derived constants +GLUSTER_CONF_DIR = GLUSTER_BASE_DIR + "/conf" +GLUSTER_TMP_DIR = GLUSTER_BASE_DIR + "/tmp" +VOLUME_CONF_DIR = GLUSTER_BASE_DIR + "/volumes" +SERVER_CONF_DIR = GLUSTER_BASE_DIR + "/servers" +DNS_RECORDS_DIR = GLUSTER_BASE_DIR + "/dns-records" +INSTALLER_CONF_DIR = SERVER_CONF_DIR + "/" + INSTALLER_SERVER_NAME + +GSN_USER_INFO_FILE = GLUSTER_BASE_DIR + "/gsn-user.info" +GLUSTER_VERSION_FILE = GLUSTER_BASE_DIR + "/version" +GLUSTER_UPDATE_SITE_FILE = GLUSTER_BASE_DIR + "/update-site" +GLUSTER_DIRECTORY_SERVICE_CONF_FILE = GLUSTER_BASE_DIR + "/directory.xml" +GLUSTER_TIME_CONF_FILE = GLUSTER_BASE_DIR + "/timeconfig.xml" +TRANSACTION_KEY_FILE = GLUSTER_BASE_DIR + "/transaction.key" +SERVER_COUNT_FILE = GLUSTER_BASE_DIR + "/server-count" +SIGNATURE_FILE = GLUSTER_BASE_DIR + "/.signature" +GLUSTER_SERVER_POOL_FILE = GLUSTER_BASE_DIR + "/pool" +GLUSTER_ADMIN_FILE = GLUSTER_BASE_DIR + "/.password" + +VOLUME_SMBCONF_FILE = VOLUME_CONF_DIR + "/volumes.smbconf.list" + +GLOBAL_NETWORK_FILE = INSTALLER_CONF_DIR + "/network.xml" +INSTALL_SERVER_CONF_FILE = INSTALLER_CONF_DIR + "/installer.xml" +INSTALLER_INFO_FILE = INSTALLER_CONF_DIR + "/installer.info" +INSTALLED_SERVER_COUNT_FILE = INSTALLER_CONF_DIR + "/installed-server-count" + +SESSION_FILE = GLUSTER_TMP_DIR + "/login.sessions" + +GENERAL_LOG_FILE = LOG_DIR + "/general.log" +INSTALLER_LOG_FILE = LOG_DIR + "/installer.log" +PEER_AGENT_LOG_FILE = LOG_DIR + "/peeragent.log" +SERVER_AGENT_LOG_FILE = LOG_DIR + "/serveragent.log" +TRANSPORT_AGENT_LOG_FILE = LOG_DIR + "/transport.log" +## + + +## Global variables +## TODO: These should be removed +DOWNLOAD_GLUSTER_UPDATE_PROCESS = None +DOWNLOAD_GLUSTER_UPDATE_LEVEL = None +DOWNLOAD_GLUSTER_CURRENT_UPDATE_LEVEL = None +DOWNLOAD_GLUSTER_UPDATE_MD5SUM = None +REQUEST_MAP = {} +VERSION_DICTONARY = {} +## + +AWS_WEB_SERVICE_URL = "http://169.254.169.254/latest" +REAL_SAMBA_CONF_FILE = "/etc/samba/real.smb.conf" diff --git a/src/com.gluster.storage.management.gateway.scripts/src/GlusterdUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/GlusterdUtils.py new file mode 100644 index 00000000..7c0e899c --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/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.gateway.scripts/src/NetworkUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/NetworkUtils.py new file mode 100755 index 00000000..42e9892c --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/NetworkUtils.py @@ -0,0 +1,483 @@ +# 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 sys + +if not "/usr/share/system-config-network/" in sys.path: + sys.path.append("/usr/share/system-config-network") + +import os +import tempfile +import Globals + +from Utils import * +#from netconfpkg.NCHardwareList import getHardwareList + +def readHostFile(fileName=None): + hostEntryList = [] + if not fileName: + fileName = "/etc/hosts" + try: + for line in open(fileName): + tokens = line.split("#")[0].strip().split() + if len(tokens) < 2: + continue + hostEntryList.append({tokens[0] : tokens[1:]}) + return hostEntryList + except IOError: + log("failed to read %s file" % fileName) + return None + + +def writeHostFile(hostEntryList, fileName=None): + if fileName: + hostFile = fileName + else: + hostFile = tempfile.mktemp(prefix="GSPSA") + try: + fp = open(hostFile, "w") + for host in hostEntryList: + fp.write("%s\t%s\n" % (host.keys()[0], " ".join(host.values()[0]))) + fp.close() + if hostFile == fileName: + return True + except IOError: + log("failed to write %s file" % hostFile) + return False + if runCommandFG("mv -f %s /etc/hosts" % hostFile, root=True) != 0: + log("failed to rename file %s to /etc/hosts" % hostFile) + return False + return True + + +def readResolvConfFile(fileName=None, includeLocalHost=False): + nameServerList = [] + domain = None + searchDomain = None + if not fileName: + fileName = Globals.RESOLV_CONF_FILE + try: + for line in open(fileName): + tokens = line.split("#")[0].strip().split() + if len(tokens) < 2: + continue + if tokens[0].upper() == "NAMESERVER": + if includeLocalHost == False and tokens[1] == "127.0.0.1": + continue + nameServerList.append(tokens[1]) + continue + if tokens[0].upper() == "DOMAIN": + domain = tokens[1:] + continue + if tokens[0].upper() == "SEARCH": + searchDomain = tokens[1:] + continue + return nameServerList, domain, searchDomain + except IOError: + log("failed to read %s file" % fileName) + return None, None, None + + +def writeResolvConfFile(nameServerList, domain, searchDomain, fileName=None, appendLocalHost=True): + if fileName: + resolvConfFile = fileName + else: + resolvConfFile = tempfile.mktemp(prefix="GSPSA") + try: + fp = open(resolvConfFile, "w") + if appendLocalHost: + fp.write("nameserver 127.0.0.1\n") + for nameServer in nameServerList: + fp.write("nameserver %s\n" % nameServer) + if domain: + fp.write("domain %s\n" % " ".join(domain)) + if searchDomain: + fp.write("search %s\n" % " ".join(searchDomain)) + fp.close() + if resolvConfFile == fileName: + return True + except IOError: + log("failed to write %s file" % resolvConfFile) + return False + if runCommandFG("mv -f %s %s" % (resolvConfFile, Globals.RESOLV_CONF_FILE), root=True) != 0: + log("failed to rename file %s to %s" % (resolvConfFile, Globals.RESOLV_CONF_FILE)) + return False + return True + + +def readIfcfgConfFile(deviceName, root=""): + conf = {} + fileName = "%s%s/ifcfg-%s" % (root, Globals.SYSCONFIG_NETWORK_DIR, deviceName) + try: + for line in open(fileName): + tokens = line.split("#")[0].split("=") + if len(tokens) != 2: + continue + conf[tokens[0].strip().lower()] = tokens[1].strip() + return conf + except IOError: + log("failed to read %s file" % fileName) + return None + + +def writeIfcfgConfFile(deviceName, conf, root="", deviceFile=None): + if not deviceFile: + deviceFile = "%s%s/ifcfg-%s" % (root, Globals.SYSCONFIG_NETWORK_DIR, deviceName) + if root: + ifcfgConfFile = deviceFile + else: + ifcfgConfFile = tempfile.mktemp(prefix="GSPSA") + try: + fp = open(ifcfgConfFile, "w") + for key in conf.keys(): + if key == "description": + fp.write("#%s=%s\n" % (key.upper(), conf[key])) + continue + if key in ['link', 'mode']: + continue + if conf["device"].startswith("bond") and key in ['hwaddr', 'master', 'slave']: + continue + if key == "slave" and conf['master']: + fp.write("SLAVE=yes\n") + continue + if key == "onboot": + if conf[key] == True: + fp.write("ONBOOT=yes\n") + elif isString(conf[key]) and conf[key].upper() == "YES": + fp.write("ONBOOT=yes\n") + else: + fp.write("ONBOOT=no\n") + continue + if not conf[key]: + continue + fp.write("%s=%s\n" % (key.upper(), conf[key])) + fp.close() + if ifcfgConfFile == deviceFile: + return True + except IOError: + log("failed to write %s file" % ifcfgConfFile) + return False + if runCommandFG("mv -f %s %s" % (ifcfgConfFile, deviceFile), root=True) != 0: + log("failed to rename file %s to %s" % (ifcfgConfFile, deviceFile)) + return False + return True + +def getNetDeviceDetail(deviceName): + deviceDetail = {} + deviceDetail['Name'] = deviceName + rv = runCommandFG("ifconfig %s" % deviceName, stdout=True, root=True) + if rv["Status"] != 0: + return False + for line in rv["Stdout"].split(): + tokens = line.strip().split(":") + if tokens[0].upper() == "ENCAP": + deviceDetail['Model'] = tokens[1].strip().upper() + break + + for line in rv["Stdout"].split("\n"): + if line.strip().startswith("inet addr:"): + tokens = line.strip().split(":") + if tokens[0].upper() == "INET ADDR": + try: + deviceDetail['Ip'] = tokens[1].strip().split()[0] + deviceDetail['Mask'] = tokens[-1].strip() + except IndexError: + pass + break + return deviceDetail + +def getNetDeviceGateway(deviceName): + rv = runCommand("route -n", output=True, root=True) + if rv["Status"] != 0: + return None + if not rv["Stdout"]: + return None + lines = [line for line in rv["Stdout"].split("\n") if line.find("UG") != -1 and line.find(deviceName)] + if not lines: + return None + line = lines[-1].split() + if line and len(line) > 1: + return line[1] + return None + +def getNetSpeed(deviceName): + rv = runCommandFG("ethtool %s" % deviceName, stdout=True, root=True) + if rv["Status"] != 0: + return False + for line in rv["Stdout"].split("\n"): + tokens = line.strip().split(":") + if tokens[0].upper() == "SPEED": + return tokens[1].strip().upper().split("MB")[0] + return None + +def getLinkStatus(deviceName): + return True + ## ethtool takes very long time to respond. So its disabled now + rv = runCommandFG("ethtool %s" % deviceName, stdout=True, root=True) + if rv["Status"] != 0: + return False + for line in rv["Stdout"].split("\n"): + tokens = line.strip().split(":") + if tokens[0].upper() == "LINK DETECTED": + if tokens[1].strip().upper() == "YES": + return True + else: + return False + return False + + +def getBondMode(deviceName, fileName=None): + if not fileName: + fileName = Globals.MODPROBE_CONF_FILE + try: + for line in open(fileName): + tokens = line.split("#")[0].split() + if len(tokens) < 4: + continue + if tokens[0].upper() == "OPTIONS" and tokens[1] == deviceName: + if tokens[2].startswith("mode="): + return tokens[2].split("=")[1] + if tokens[3].startswith("mode="): + return tokens[3].split("=")[1] + if tokens[4].startswith("mode="): + return tokens[4].split("=")[1] + if tokens[5].startswith("mode="): + return tokens[5].split("=")[1] + return None + except IOError: + log("failed to read %s file" % fileName) + return None + + +def setBondMode(deviceName, mode, fileName=None): + if not fileName: + fileName = Globals.MODPROBE_CONF_FILE + tempFileName = getTempFileName() + try: + fp = open(tempFileName, "w") + lines = open(fileName).readlines() + except IOError: + log("unable to open file %s" % Globals.MODPROBE_CONF_FILE) + return False + for line in lines: + tokens = line.split() + if len(tokens) > 1 and "OPTIONS" == tokens[0].upper() and "BOND" in tokens[1].upper() and deviceName == tokens[1]: + fp.write("options %s max_bonds=2 mode=%s miimon=100\n" % (deviceName, mode)) + deviceName = None + continue + fp.write(line) + if deviceName: + fp.write("alias %s bonding\n" % deviceName) + fp.write("options %s max_bonds=2 mode=%s miimon=100\n" % (deviceName, mode)) + fp.close() + if runCommandFG(["mv", "-f", tempFileName, fileName], root=True) != 0: + log("unable to move file from %s to %s" % (tempFileName, fileName)) + return False + return True + +def getNetDeviceList(root=""): + netDeviceList = [] + for deviceName in os.listdir("/sys/class/net/"): + netDevice = {} + netDevice["device"] = None + netDevice["description"] = None + netDevice["hwaddr"] = None + netDevice["type"] = None + netDevice["onboot"] = None + netDevice["bootproto"] = None + netDevice["gateway"] = None + netDevice["peerdns"] = None + netDevice["autodns"] = None + netDevice["dns1"] = None + netDevice["dns2"] = None + netDevice["dns3"] = None + netDevice["master"] = None + netDevice["slave"] = None + netDevice["nmcontrolled"] = None + netDevice["link"] = None + netDevice["mode"] = None + + #netDevice["device"] = device.Name + netDevice["device"] = deviceName + #netDevice["description"] = device.Description + netDevice["description"] = deviceName + #netDevice["type"] = device.Type + netDevice["type"] = None + netDevice["link"] = getLinkStatus(deviceName) + netDevice["mode"] = getBondMode(deviceName, root + Globals.MODPROBE_CONF_FILE) + deviceDetail = getNetDeviceDetail(deviceName) + if deviceDetail.has_key('Model'): + netDevice["model"] = deviceDetail['Model'] + else: + netDevice["model"] = None + if deviceDetail.has_key('Ip'): + netDevice["ipaddr"] = deviceDetail['Ip'] + else: + netDevice["ipaddr"] = None + if deviceDetail.has_key('Mask'): + netDevice["netmask"] = deviceDetail['Mask'] + else: + netDevice["netmask"] = None + netDevice["speed"] = getNetSpeed(deviceName) + try: + netDevice["hwaddr"] = open("/sys/class/net/%s/address" % deviceName).read().strip() + except IOError: + pass + + netDeviceList.append(netDevice) + + conf = readIfcfgConfFile(deviceName, root) + if not conf: + continue + try: + netDevice["onboot"] = conf["onboot"] + except KeyError: + pass + try: + netDevice["bootproto"] = conf["bootproto"] + except KeyError: + pass + if conf.has_key("ipaddr") and conf["ipaddr"]: + netDevice["ipaddr"] = conf["ipaddr"] + try: + netDevice["netmask"] = conf["netmask"] + except KeyError: + pass + if conf.has_key("gateway") and conf["gateway"]: + netDevice["gateway"] = conf["gateway"] + else: + netDevice["gateway"] = getNetDeviceGateway(deviceName) + try: + netDevice["peerdns"] = conf["peerdns"] + except KeyError: + pass + try: + netDevice["autodns"] = conf["autodns"] + except KeyError: + pass + try: + netDevice["dns1"] = conf["dns1"] + except KeyError: + pass + try: + netDevice["dns2"] = conf["dns2"] + except KeyError: + pass + try: + netDevice["dns3"] = conf["dns3"] + except KeyError: + pass + try: + netDevice["master"] = conf["master"] + except KeyError: + pass + try: + netDevice["slave"] = conf["slave"] + except KeyError: + pass + try: + netDevice["nmcontrolled"] = conf["nmcontrolled"] + except KeyError: + pass + + return netDeviceList + + ## bondDevices = [os.path.basename(device) for device in glob.glob("/sys/class/net/bond*")] + + ## bondDevices = [os.path.basename(device) for device in glob.glob("/sys/class/net/bond*")] + ## for deviceName in bondDevices: + ## if deviceName in linkedBondList: + ## if deviceName in sysConfigDeviceList: + ## deviceList[deviceName] = sysConfigDeviceList[deviceName] + ## else: + ## deviceList[deviceName] = {'device':deviceName, 'onboot':'no', 'bootproto':'none'} + ## continue + ## if len(ethDevices) > 2: + ## deviceList[deviceName] = {'device':deviceName, 'onboot':'no', 'bootproto':'none'} + + +def configureDhcpServer(serverIpAddress, dhcpIpAddress): + tmpDhcpConfFile = tempfile.mktemp(prefix="GSPSA") + + serverPortString = "68" + try: + for arg in open("/proc/cmdline").read().strip().split(): + token = arg.split("=") + if token[0] == "dhcp": + serverPortString = token[1] + break + except IOError: + log(syslog.LOG_ERR, "Failed to read /proc/cmdline. Continuing with default port 68") + try: + serverPort = int(serverPortString) + except ValueError: + log(syslog.LOG_ERR, "Invalid dhcp port '%s' in /proc/cmdline. Continuing with default port 68" % serverPortString) + serverPort = 68 + + try: + fp = open(tmpDhcpConfFile, "w") + fp.write("bind-interfaces\n") + fp.write("except-interface=lo\n") + fp.write("dhcp-range=%s,%s\n" % (dhcpIpAddress, dhcpIpAddress)) + fp.write("dhcp-lease-max=1\n") + fp.write("dhcp-alternate-port=%s\n" % serverPort) + fp.write("dhcp-leasefile=%s\n" % Globals.DNSMASQ_LEASE_FILE) + #fp.write("server=%s\n" % serverIpAddress) + #fp.write("dhcp-script=/usr/sbin/server-info\n") + fp.close() + except IOError: + log(syslog.LOG_ERR, "unable to write dnsmasq dhcp configuration %s" % tmpDhcpConfFile) + return False + if runCommandFG("mv -f %s %s" % (tmpDhcpConfFile, Globals.DNSMASQ_DHCP_CONF_FILE), root=True) != 0: + log(syslog.LOG_ERR, "unable to copy dnsmasq dhcp configuration to %s" % Globals.DNSMASQ_DHCP_CONF_FILE) + return False + return True + + +def isDhcpServer(): + return os.path.exists(Globals.DNSMASQ_DHCP_CONF_FILE) + + +def getDhcpServerStatus(): + if runCommandFG("service dnsmasq status", root=True) == 0: + return True + return False + + +def startDhcpServer(): + if runCommandFG("service dnsmasq start", root=True) == 0: + return True + return False + + +def stopDhcpServer(): + if runCommandFG("service dnsmasq stop", root=True) == 0: + runCommandFG("rm -f %s" % Globals.DNSMASQ_LEASE_FILE, root=True) + return True + return False + + +def restartDhcpServer(): + stopDhcpServer() + runCommandFG("rm -f %s" % Globals.DNSMASQ_LEASE_FILE, root=True) + return startDhcpServer() + + +def reloadDhcpServer(): + if runCommandFG("service dnsmasq reload", root=True) == 0: + return True + return False diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Protocol.py b/src/com.gluster.storage.management.gateway.scripts/src/Protocol.py new file mode 100644 index 00000000..ff073593 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Protocol.py @@ -0,0 +1,438 @@ +# Copyright (C) 2009 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 xml +import xml.parsers.expat +import xml.dom.minidom as MDOM +import os +import Globals +import copy +import Utils + +XML_STRING = 0 +XML_FILE = 1 + +class XDOM: + _domObj = None + + def __init__(self): + self._domObj = MDOM.Document() + return + + @classmethod + def getText(self, nodeList): + rc = "" + for node in nodeList: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc.strip() + + def parseString(self, requestString): + try: + self._domObj = MDOM.parseString(requestString) + except xml.parsers.expat.ExpatError, e: + Utils.log("XML string parse error: %s" % str(e)) + return False + return True + + def parseFile(self, fileName): + try: + self._domObj = MDOM.parse(fileName) + except IOError, e: + Utils.log("error reading file: %s" % str(e)) + return False + except xml.parsers.expat.ExpatError, e: + Utils.log("XML file %s parse error: %s" % (fileName, str(e))) + return False + return True + + def setDomObj(self, dom): + if dom and type(dom) != type([]): + self._domObj = dom + return True + return False + + def createTextNode(self, text): + if not self._domObj: + return False + if not text: + return False + return self._domObj.createTextNode(str(text)) + + def createTag(self, tag, text=None): + if not self._domObj: + return None + if tag == None: + return None + + tagE = self._domObj.createElement(str(tag)) + if text: + tagEText = self._domObj.createTextNode(str(text)) + tagE.appendChild(tagEText) + return tagE + + def addTag(self, tag): + if not self._domObj: + return False + if not tag: + return False + + self._domObj.appendChild(tag) + return True + + def createTagRoute(self, tagRoute, text=None): + if not tagRoute: + return False + + tagList = tagRoute.split(".") + tag = None + previousTag = None + for tagName in tagList[:-1]: + newTag = self.createTag(tagName, None) + if not tag: + tag = newTag + previousTag = newTag + continue + previousTag.appendChild(newTag) + previousTag = newTag + + if previousTag: + previousTag.appendChild(self.createTag(tagList[-1], text)) + else: + tag = self.createTag(tagList[-1], text) + return tag + + def appendTagRoute(self, tagRoute, value=None): + if not self._domObj: + return False + if not tagRoute: + return False + + parentTagE = self._domObj + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True + + def setTextByTagRoute(self, tagRoute, tagValue): + if not self._domObj: + return None + + if not tagRoute: + return None + + tagE = self.getElementsByTagRoute(tagRoute) + if not tagE: + return False + + parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1])) + if not parentTagE: + return False + + parentTagE[0].childNodes.remove(tagE[0]) + parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue)) + return True + + def getElementsByTagRoute(self, tagRoute): + if not self._domObj: + return None + + if not tagRoute: + return None + + x = None + for tag in tagRoute.split("."): + if x is None: + x = self._domObj.getElementsByTagName(tag) + continue + if x == []: + break + x = x[0].getElementsByTagName(tag) + return x + + def getTextByTagRoute(self, tagRoute): + if not self._domObj: + return None + + x = self.getElementsByTagRoute(tagRoute) + if x: + return self.getText(x[0].childNodes) + return None + + def getElementsByTagName(self, name): + if not self._domObj: + return None + return self._domObj.getElementsByTagName(name) + + def writexml(self, fileName, indent="", addindent="", newl=""): + if not self._domObj: + return None + try: + fp = open(fileName, "w") + self._domObj.writexml(fp, indent, addindent, newl) + fp.close() + return True + except IOError: + return False + + def toString(self, indent=" ", newl="\n", encoding = None): + if not self._domObj: + return None + return self._domObj.toprettyxml(indent, newl, encoding) + + def toxml(self, encoding = None): + if not self._domObj: + return None + return self._domObj.toxml(encoding) + + def toprettyxml(self, indent=" ", newl="\n", encoding = None): + return self.toString(indent, newl, encoding) + + def getAttribute(self, attributeName): + if not attributeName: + return None + try: + return self.getElementsByTagName("command")[0].getAttribute(attributeName) + except IndexError: + return False + + def setAttribute(self, attributeName, attributeValue): + if not (attributeName and attributeValue): + return None + try: + return self.getElementsByTagName("command")[0].setAttribute(attributeName, attributeValue) + except IndexError: + return False + + def getRequestCommand(self): + return self.getAttribute("request") + + def getResponseCommand(self): + return self.getAttribute("response") + + def getResponseCode(self): + return self.getAttribute("response-code") + + def getMessageId(self): + return self.getAttribute("id") + + def getVersion(self): + return self.getAttribute("version") + + def getRequestAction(self): + return self.getAttribute("action") + + def setVersion(self, value): + return self.setAttribute("version", value) + + def setRequestAction(self, value): + return self.setAttribute("action", value) + + def createCommandTag(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + commandTag = self._domObj.createElement("command") + commandTag.setAttribute("response", command) + commandTag.setAttribute("response-code", responseCode) + commandTag.setAttribute("id", id) + commandTag.setAttribute("version", version) + return commandTag +##--end of XDOM + +class RequestXml(XDOM): + def __init__(self, requestString, type=None): + if None == requestString: + XDOM.__init__(self) + return + try: + if None == type: + if os.path.isfile(requestString): + self._domObj = MDOM.parse(requestString) + else: + self._domObj = MDOM.parseString(requestString) + elif XML_FILE == type: + self._domObj = MDOM.parse(requestString) + elif XML_STRING == type: + self._domObj = MDOM.parseString(requestString) + except IOError: + XDOM.__init__(self) + except xml.parsers.expat.ExpatError: + XDOM.__init__(self) + +##--end of RequestXML + +class ResponseXml(XDOM): + _commandTag = None + def __init__(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + XDOM.__init__(self) + if command and responseCode and id: + self._commandTag = self.createCommandTag(command, responseCode, id, version) + self._domObj.appendChild(self._commandTag) + + def appendCommand(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + if command and responseCode and id: + self._commandTag = self.createCommandTag(command, responseCode, id, version) + self._domObj.appendChild(self._commandTag) + return True + return False + + def append(self, tagName, tagValue=None): + if not self._commandTag: + return False + tag = self.createTag(tagName, tagValue) + if tag: + self._commandTag.appendChild(tag) + return True + return False + + def appendTag(self, tag): + if not tag: + return False + if not self._commandTag: + return False + self._commandTag.appendChild(tag) + return True + + def appendTagRoute(self, tagRoute, value=None): + if not self._commandTag: + return False + if not tagRoute: + return False + + parentTagE = self._commandTag + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(["command"] + tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True + + def appendTagRouteOld(self, tagRoute, value=None): + if not tagRoute: + return False + if not self._commandTag: + return False + + tmpTagRoute = "" + previousTagE = self._commandTag + tagE = None + for tagName in tagRoute.split("."): + if not tmpTagRoute: + tagE = self.getElementsByTagRoute("command." + tagName) + else: + tagE = self.getElementsByTagRoute("command." + tmpTagRoute + "." + tagName) + if not tagE: + break + if len(tagE) != 1: + return False + previousTagE = tagE[0] + if not tmpTagRoute: + tmpTagRoute = tagName + else: + tmpTagRoute = tmpTagRoute + "." + tagName + + if tmpTagRoute == tagRoute: + return False + newTagRoute = tagRoute[len(tmpTagRoute):] + if newTagRoute[0] == '.': + newTagRoute = newTagRoute[1:] + + if previousTagE.childNodes and previousTagE.childNodes[0].nodeType == previousTagE.TEXT_NODE: + return False + previousTagE.appendChild(self.createTagRoute(newTagRoute, value)) + return True +##--end of ResponseXml + +def test(): + #volumes = RequestXml(VolumeFile, XML_FILE).getElementsByTagRoute("volume-list.volume") + requestStr = '''<command request="create-volume" id="123" version="3.1"> +<volume> +<name>movies1</name> +<type>cluster mirror</type> +<start>512000</start> +<server>zresearch</server> +<vacl>192.168.20.*</vacl> +<vacl>192.168.30.*</vacl> +<nfs> +<export>no</export> +</nfs> +<cifs> +<export>no</export> +</cifs> +<webdav> +<export>no</export> +</webdav> +</volume> +</command>''' + + requestXml = RequestXml(requestStr) + print requestXml.getAttribute("") + +def test1(): + rs = ResponseXml("create-volume", "OK", "xyz") + rs.appendTagRoute("volume.detail.name", "music") + print rs.toprettyxml() + rs.append("volume", "data") + print rs.toprettyxml() + rs.appendTagRoute("volume.detail.ipaddr", "192.168.10.1") + print rs.toprettyxml() + print rs.appendTagRoute("volume.detail.ipaddr.v6", "ff:ff::ff::") + print rs.toprettyxml() + + print rs.getTextByTagRoute("command.volume.detail") + +def test2(): + rs = ResponseXml("download-volume-logs", "OK", "xyz") + te = rs.createTag("interface", None) + te.appendChild(rs.createTag("device", "DEVICE1")) + te.appendChild(rs.createTag("description", "my device one")) + rs.appendTag(te) + + te = rs.createTag("interface", None) + te.appendChild(rs.createTag("device", "DEVICE2")) + te.appendChild(rs.createTag("description", "my device two")) + rs.appendTag(te) + print rs.toprettyxml() + diff --git a/src/com.gluster.storage.management.gateway.scripts/src/RRDUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/RRDUtils.py new file mode 100644 index 00000000..1ad0deee --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/RRDUtils.py @@ -0,0 +1,72 @@ +import rrdtool +import os +from socket import gethostname +from itertools import groupby + +class RRD: + def __init__ (self): + self.COLORS = [0xff7777, 0x7777ff, 0x55ff55, 0xffcc77, 0xff77ff, 0x77ffff,0xffff77, 0x55aaff] + self.HOST = gethostname() + self.DIR = "/var/lib/collectd" + + def fade_component(self, component): + return ((component + 255 * 5) / 6) + + def fade_color(self, color): + r = 0; + for i in [0,1,2]: + shft = (i * 8) + component = ((color >> shft) & 255) + r |= (self.fade_component(component) << shft) + return r + + def generate_pngs(self): + + rrdlist = os.popen ("find %s -type f -name '*.rrd'" % self.DIR) + + for rrd in rrdlist: + self.dss = [] + self.defs = "" + + rrdinfo = rrdtool.info(rrd.strip()) + + for key in rrdinfo.keys(): + if key.split('[')[0] == 'ds': + self.dss.append(key.split('[')[1].split(']')[0]) + self.dss.sort() + + self.dss = [a for a,b in groupby(self.dss)] + + for ds in self.dss: + self.defs = self.defs + " DEF:%s_avg=%s:%s:AVERAGE " % (ds, rrd.strip(), ds) + self.defs = self.defs + " DEF:%s_max=%s:%s:MAX " % (ds, rrd.strip(), ds) + + j = 0 + for ds in self.dss: + color = self.COLORS[j % len(self.COLORS)] + j = j + 1 + faded_color = self.fade_color(color) + self.defs = self.defs + " AREA:%s_max#%06x " % (ds, faded_color) + + j = 0 + for ds in self.dss: + color = self.COLORS[j % len(self.COLORS)] + j = j + 1 + self.defs = self.defs + " LINE2:%s_avg#%06x:%s " % (ds, color, ds) + self.defs = self.defs + " GPRINT:%s_avg:AVERAGE:%%5.1lf%%sAvg " % ds + self.defs = self.defs + " GPRINT:%s_max:MAX:%%5.1lf%%sMax " % ds + + for span in ['1hour', '1day', '1week', '1month']: + os.system ("mkdir -p %s/%s" % (self.DIR, self.HOST)) + image = os.path.dirname(rrd.strip()) + "-" + span + ".png" + cmd = "rrdtool graph " + image + " -t \"%s %s\"" % (os.path.dirname(rrd.strip()), span) + " --imgformat PNG --width 600 --height 100 --start now-" + span + " --end now --interlaced " + self.defs + " >/dev/null 2>&1" + os.system(cmd) + + +def main (): + + rrd = RRD () + rrd.generate_pngs () + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/ServerUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/ServerUtils.py new file mode 100644 index 00000000..1fec994c --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/ServerUtils.py @@ -0,0 +1,308 @@ +# 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 re +import subprocess +import glob +import Globals +from Protocol import * +from Utils import * + +def isValidServer(serverName): + for profile in getProfileList(): + if profile.ProfileName == "default" and profile.Active: + if serverName == profile.DNS.Hostname: + return True + return False + +def getHostname(): + for profile in getProfileList(): + if profile.ProfileName == "default" and profile.Active: + return profile.DNS.Hostname + return None + +def getDomainName(): + try: + domainName = open(Globals.DOMAINNAME_FILE).read() + except IOError: + return None + return domainName.split()[0] + +def replaceServerIp(fileName, findWhat, replaceWith): + try: + data = open(fileName).read() + fp = open(fileName, "w") + fp.write(re.sub(findWhat, replaceWith, data)) + fp.close() + return True + except IOError: + return False + except ValueError: + return False + except OSError: + return False + +def serverName2IpAddress(serverName): + command = "dig %s | grep '^%s'" % (serverName, serverName) + ps = subprocess.Popen(command, + shell=True, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + ipAddress = serverName + if ps.wait() == 0: + output = ps.communicate() + ipAddress = output[0].split()[-1] + return ipAddress + +def getInstallerIp(): + if not os.path.exists(Globals.INSTALLER_INFO_FILE): + return None + try: + for line in open(Globals.INSTALLER_INFO_FILE): + tokens = line.split("=") + if tokens[0] == "IP-ADDRESS": + return tokens[1].split(",")[0].strip() + except IOError: + syslog.syslog(syslog.LOG_ERR, "unable to read %s file" % Globals.INSTALLER_INFO_FILE) + return False + +def setInstallerIp(installerIp): + try: + open(Globals.INSTALLER_INFO_FILE, "w").write("IP-ADDRESS=%s\n" % installerIp) + return True + except IOError: + log(syslog.LOG_ERR, "unable to create %s file" % Globals.INSTALLER_INFO_FILE) + return False + +def getCurrentServerName(): + try: + for line in open(Globals.SYSCONFIG_NETWORK_FILE): + tokens = line.split("=") + if tokens[0] == "HOSTNAME": + return tokens[1].strip() + except IOError: + syslog.syslog(syslog.LOG_ERR, "unable to read %s file" % Globals.SYSCONFIG_NETWORK_FILE) + return False + +def getLastAccessedNetwork(serverName): + lastAccessedNetworkFile = ("/%s/servers/%s/%s" % + (Globals.GLUSTER_CONF_DIR, serverName, Globals.LAST_ACCESSED_NETWORK_FILE)) + try: + return open(lastAccessedNetworkFile).read().strip() + except IOError: + log(syslog.LOG_ERR, "failed to read last accessed network file %s" % lastAccessedNetworkFile) + pass + return False + +def setLastAccessedNetwork(serverName, ipAddress): + lastAccessedNetworkFile = ("/%s/servers/%s/%s" % + (Globals.GLUSTER_CONF_DIR, serverName, Globals.LAST_ACCESSED_NETWORK_FILE)) + try: + open(lastAccessedNetworkFile, "w").write(ipAddress.strip() + "\n") + except IOError: + log(syslog.LOG_ERR, "failed to write last accessed network file %s" % lastAccessedNetworkFile) + return False + return True + +def getServerIpList(serverName, preferredNetworkOnly=False): + networkXmlFile = ("%s/servers/%s/network.xml" % (Globals.GLUSTER_CONF_DIR, serverName)) + configDom = XDOM() + if not configDom.parseFile(networkXmlFile): + log(syslog.LOG_ERR, "failed to read %s file" % networkXmlFile) + return None + preferredNetwork = configDom.getTextByTagRoute("preferred-network") + ipList = [] + interfaceDom = XDOM() + for tagE in configDom.getElementsByTagName("interface"): + interfaceDom.setDomObj(tagE) + deviceName = interfaceDom.getTextByTagRoute("device") + hostIp = interfaceDom.getTextByTagRoute("ipaddr") + if not hostIp: + continue + if preferredNetworkOnly: + if preferredNetwork.upper() == "ANY" or preferredNetwork.upper() == deviceName.upper(): + ipList.append(hostIp) + else: + ipList.append(hostIp) + if preferredNetworkOnly: + lastAccessedNetworkIp = getLastAccessedNetwork(serverName) + if lastAccessedNetworkIp in ipList: + ipList.remove(lastAccessedNetworkIp) + ipList = [lastAccessedNetworkIp] + ipList + return ipList + +def getServerPreferredIpList(serverName): + return getServerIpList(serverName, True) + +def getExecuteServerList(serverList): + executeServerList = {} + for serverName in serverList: + if serverName == Globals.INSTALLER_SERVER_NAME: + installerIp = getInstallerIp() + if installerIp: + executeServerList[serverName] = [installerIp] + continue + executeServerList[serverName] = getServerPreferredIpList(serverName) + return executeServerList + +def getAllServerList(): + serverList = [] + for filePath in glob.glob("%s/servers/*" % Globals.GLUSTER_CONF_DIR): + if os.path.isdir(filePath): + serverList.append(os.path.basename(filePath)) + try: + serverList.remove(Globals.INSTALLER_SERVER_NAME) + except ValueError: + pass + return serverList + +def getServerNetworkConfigFromLocalFile(serverName): + configDom = XDOM() + configDom.parseFile("%s/servers/%s/network.xml" % (Globals.GLUSTER_CONF_DIR, serverName)) + return configDom + +def updateServerNetworkConfigXmlFile(serverName, serverNetworkDom): + configDom = XDOM() + serverTag = serverNetworkDom.getElementsByTagRoute("server")[0] + configDom.setDomObj(serverTag) + if not configDom.writexml("%s/%s/network.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)): + log("Faild to write xml file %s/%s/network.xml" % (Globals.SERVER_VOLUME_CONF_DIR, serverName)) + +def compareServerNetworkDom(serverNetworkDomA, serverNetworkDomB, requestFlag=True): + command = "command.server." + if not requestFlag: + command = "" + sourceServer = {} + tagText = serverNetworkDomA.getTextByTagRoute("name") + if not tagText: + taxText = None + sourceServer["name"] = tagText + tagText = serverNetworkDomA.getTextByTagRoute("domain-name") + if not tagText: + tagText = None + sourceServer["domain-name"] = tagText + tagText = serverNetworkDomA.getTextByTagRoute("search-domain") + if not tagText: + tagText = None + sourceServer["search-domain"] = tagText + tagText = serverNetworkDomA.getTextByTagRoute("dns1") + if not tagText: + tagText = None + sourceServer["dns1"] = tagText + tagText = serverNetworkDomA.getTextByTagRoute("dns2") + if not tagText: + tagText = None + sourceServer["dns2"] = tagText + tagText = serverNetworkDomA.getTextByTagRoute("dns3") + if not tagText: + tagText = None + sourceServer["dns3"] = tagText + for tagE in serverNetworkDomA.getElementsByTagRoute("interface"): + interfaceDom = XDOM() + interfaceDom.setDomObj(tagE) + sourceServerList = {} + tagText = interfaceDom.getTextByTagRoute("description") + if not tagText: + tagText = None + sourceServerList["description"] = tagText + tagText = interfaceDom.getTextByTagRoute("hwaddr") + if not tagText: + tagText = None + sourceServerList["hwaddr"] = tagText + tagText = interfaceDom.getTextByTagRoute("onboot") + if not tagText: + tagText = None + sourceServerList["onboot"] = tagText + tagText = interfaceDom.getTextByTagRoute("bootproto") + if not tagText: + tagText = None + sourceServerList["bootproto"] = tagText + tagText = interfaceDom.getTextByTagRoute("ipaddr") + if not tagText: + tagText = None + sourceServerList["ipaddr"] = tagText + tagText = interfaceDom.getTextByTagRoute("netmask") + if not tagText: + tagText = None + sourceServerList["netmask"] = tagText + tagText = interfaceDom.getTextByTagRoute("gateway") + if not tagText: + tagText = None + sourceServerList["gateway"] = tagText + sourceServer[interfaceDom.getTextByTagRoute("device")] = sourceServerList + objServer = {} + tagText = serverNetworkDomB.getTextByTagRoute(command + "name") + if not tagText: + taxText = None + objServer["name"] = tagText + tagText = serverNetworkDomB.getTextByTagRoute(command + "domain-name") + if not tagText: + tagText = None + objServer["domain-name"] = tagText + tagText = serverNetworkDomB.getTextByTagRoute(command + "search-domain") + if not tagText: + tagText = None + objServer["search-domain"] = tagText + tagText = serverNetworkDomB.getTextByTagRoute(command + "dns1") + if not tagText: + tagText = None + objServer["dns1"] = tagText + tagText = serverNetworkDomB.getTextByTagRoute(command + "dns2") + if not tagText: + tagText = None + objServer["dns2"] = tagText + tagText = serverNetworkDomB.getTextByTagRoute(command + "dns3") + if not tagText: + tagText = None + objServer["dns3"] = tagText + for tagE in serverNetworkDomB.getElementsByTagRoute(command + "interface"): + interfaceDom = XDOM() + interfaceDom.setDomObj(tagE) + objServerList = {} + tagText = interfaceDom.getTextByTagRoute("description") + if not tagText: + tagText = None + objServerList["description"] = tagText + tagText = interfaceDom.getTextByTagRoute("hwaddr") + if not tagText: + tagText = None + objServerList["hwaddr"] = tagText + tagText = interfaceDom.getTextByTagRoute("onboot") + if not tagText: + tagText = None + objServerList["onboot"] = tagText + tagText = interfaceDom.getTextByTagRoute("bootproto") + if not tagText: + tagText = None + objServerList["bootproto"] = tagText + tagText = interfaceDom.getTextByTagRoute("ipaddr") + if not tagText: + tagText = None + objServerList["ipaddr"] = tagText + tagText = interfaceDom.getTextByTagRoute("netmask") + if not tagText: + tagText = None + objServerList["netmask"] = tagText + tagText = interfaceDom.getTextByTagRoute("gateway") + if not tagText: + tagText = None + objServerList["gateway"] = tagText + objServer[interfaceDom.getTextByTagRoute("device")] = objServerList + return sourceServer == objServer diff --git a/src/com.gluster.storage.management.gateway.scripts/src/Utils.py b/src/com.gluster.storage.management.gateway.scripts/src/Utils.py new file mode 100644 index 00000000..3408c14a --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/Utils.py @@ -0,0 +1,1059 @@ +# 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 sys +import os +import re +import socket +import struct +import syslog +import subprocess +#import spwd +import time +#import uuid +import tempfile +import grp +import pwd +import inspect +from datetime import datetime +import urllib + +import Globals +import Protocol + +RUN_COMMAND_ERROR = -1024 +LOG_SYSLOG = 1 +SYSLOG_REQUIRED = False +LOG_FILE_NAME = None +LOG_FILE_OBJ = None + + +def _getLogCode(priority): + if syslog.LOG_EMERG == priority: + return "M" + elif syslog.LOG_ALERT == priority: + return "A" + elif syslog.LOG_CRIT == priority: + return "C" + elif syslog.LOG_ERR == priority: + return "E" + elif syslog.LOG_WARNING == priority: + return "W" + elif syslog.LOG_NOTICE == priority: + return "N" + elif syslog.LOG_INFO == priority: + return "I" + elif syslog.LOG_DEBUG == priority: + return "D" + else: # UNKNOWN + return "X" + + +def setLogFile(fileName): + global LOG_FILE_NAME + + if fileName: + LOG_FILE_NAME = fileName + return True + return False + + +def closeLog(): + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + if SYSLOG_REQUIRED: + syslog.closelog() + SYSLOG_REQUIRED = False + return True + + if LOG_FILE_OBJ: + try: + LOG_FILE_OBJ.close() + LOG_FILE_OBJ = None + except IOError, e: + sys.stderr.write("Failed to close file: %s\n" % e) + return False + return True + + +def openLog(fileName=None): + global LOG_FILE_NAME + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + if fileName == LOG_SYSLOG: + syslog.openlog(os.path.basename(sys.argv[0])) + SYSLOG_REQUIRED = True + return True + + if fileName: + LOG_FILE_NAME = fileName + + if not LOG_FILE_NAME: + return False + + closeLog() + + try: + LOG_FILE_OBJ = open(LOG_FILE_NAME, "a") + except IOError, e: + sys.stderr.write("Failed to open file %s: %s\n" % (LOG_FILE_NAME, e)) + return False + return True + +def record(priority, message=None): + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + stack = inspect.stack()[1] + if stack[3] == "<module>": + prefix = "%s:%s:%s" % (stack[1], stack[2], stack[3]) + else: + prefix = "%s:%s:%s()" % (stack[1], stack[2], stack[3]) + + if type(priority) == type("") or type(priority) == type(u""): + logPriority = syslog.LOG_INFO + logMessage = priority + else: + logPriority = priority + logMessage = message + + if SYSLOG_REQUIRED: + syslog.syslog(logPriority, "[%s]: %s" % (prefix, logMessage)) + return + + fp = sys.stderr + if LOG_FILE_OBJ: + fp = LOG_FILE_OBJ + + fp.write("[%s] %s [%s]: %s" % (str(datetime.now()), _getLogCode(logPriority), prefix, logMessage)) + if logMessage[-1] != '\n': + fp.write("\n") + fp.flush() + return + + +def trace(message): + if message: + log(syslog.LOG_DEBUG, message) + + +def isString(value): + return (type(value) == type("") or type(value) == type(u"")) + + +def getTempFileName(): + filedesc, filename = tempfile.mkstemp(prefix="GSP_") + os.close(filedesc) + return filename + + +def runCommandBG(command, stdinFileObj=None, stdoutFileObj=None, stderrFileObj=None, + shell=False, root=None): + log("runCommandBG(): Trying to execute command [%s]" % command) + + if shell: + if not isString(command): + return None + else: + if isString(command): + command = command.split() + + if root == True: + if shell: + command = "sudo " + command + else: + command = ['sudo'] + command + elif isString(root): + if shell: + command = "sudo -u " + root + " " + command + else: + command = ['sudo', '-u', root] + command + + if not stdinFileObj: + stdinFileObj=subprocess.PIPE + if not stdoutFileObj: + stdoutFileObj=subprocess.PIPE + if not stderrFileObj: + stderrFileObj=subprocess.PIPE + + try: + process = subprocess.Popen(command, + bufsize=-1, + stdin=stdinFileObj, + stdout=stdoutFileObj, + stderr=stderrFileObj, + shell=shell) + return process + except OSError, e: + log("runCommandBG(): Failed to run command [%s]: %s" % (command, e)) + return None + + +def runCommand(command, + input='', output=False, + shell=False, root=None): + rv = {} + rv["Status"] = RUN_COMMAND_ERROR + rv["Stdout"] = None + rv["Stderr"] = None + + try: + stdinFileName = getTempFileName() + stdinFileObj = open(stdinFileName, "w") + stdinFileObj.write(input) + stdinFileObj.close() + stdinFileObj = open(stdinFileName, "r") + + stdoutFileName = getTempFileName() + stdoutFileObj = open(stdoutFileName, "w") + + stderrFileName = getTempFileName() + stderrFileObj = open(stderrFileName, "w") + except IOError, e: + log("Failed to create temporary file for executing command [%s]: %s" % (command, e)) + if output: + return rv + return rv["Status"] + + stdoutContent = None + stderrContent = None + + process = runCommandBG(command, + stdinFileObj=stdinFileObj, + stdoutFileObj=stdoutFileObj, + stderrFileObj=stderrFileObj, + shell=shell, root=root) + if process: + rv['Status'] = process.wait() + rv['Stdout'] = open(stdoutFileName).read() + rv['Stderr'] = open(stderrFileName).read() + + os.remove(stdinFileName) + os.remove(stdoutFileName) + os.remove(stderrFileName) + + log("runCommand(): execution status of command [%s] = [%s]" % (command, rv)) + + if output: + return rv + return rv["Status"] + + +def runCommandFG(command, stdout=False, stderr=False, + shell=False, root=None): + if stdout or stderr: + output = True + else: + output = False + return runCommand(command, output=output, shell=shell, root=root) + + +def IP2Number(ipString): + try: + return socket.htonl(struct.unpack("I", socket.inet_aton(ipString))[0]) + except socket.error: + return None + except TypeError: + return None + except struct.error: + return None + + +def Number2IP(number): + try: + return socket.inet_ntoa(struct.pack("I", socket.ntohl(number))) + except socket.error: + return None + except AttributeError: + return None + except ValueError: + return None + + +def computeHostName(hostName): + if not hostName: + return False + + hostPrefix = "" + for i in range(len(hostName), 0, -1): + pos = i - 1 + if hostName[pos].isdigit(): + continue + break + hostPrefix = hostName[:pos+1] + try: + hostIndex = int(hostName[pos+1:]) + except ValueError: + hostIndex = 0 + # TODO: Check the availablity of the (server) name + return "%s%s" % (hostPrefix, hostIndex + 1) + + +def daemonize(): + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file("/dev/null", 'r') + so = file("/dev/null", 'a+') + se = file("/dev/null", 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + return True + + +def getDownloadStatus(fileName): + try: + lines = [line for line in open(fileName) + if "saved" in line or "%" in line] + except IOError: + return 0 + if not lines: + return 0 + if "saved" in lines[-1]: + return 100 + return lines[-1].split("%")[0].split()[-1] + + +def getMeminfo(): + """-> dict of data from meminfo (str:int). + Values are in kilobytes. + """ + import re + re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB' ) + result = {} + for line in open('/proc/meminfo'): + match = re_parser.match(line) + if not match: + continue # skip lines that don't parse + key, value = match.groups(['key', 'value']) + result[key] = int(value) + result['MemUsed'] = (result['MemTotal'] - result['MemFree']) + return result + + +def getCpuUsage(): + """-> dict of cpuid : (usertime, nicetime, systemtime, idletime) + cpuid "cpu" means the total for all CPUs. + cpuid "cpuN" means the value for CPU N. + """ + wanted_records = [line for line in open('/proc/stat') if + line.startswith('cpu')] + result = {} + for cpuline in wanted_records: + fields = cpuline.split()[:5] + data = map(int, fields[1:]) + result[fields[0]] = tuple(data) + return result + +def _getCpuStatList(): + try: + fp = open("/proc/stat") + cpuStatList = map(float, fp.readline().split()[1:]) + fp.close() + return cpuStatList + except IOError, e: + Utils.log("Failed to open /proc/stat: %s" % str(e)) + return None + +def getCpuUsageAvg(): + st1 = _getCpuStatList() + time.sleep(2) + st2 = _getCpuStatList() + if not (st1 and st2): + return None + delta = [st2[i] - st1[i] for i in range(len(st1))] + cpuPercent = sum(delta[:3]) / delta[3] * 100.0 + return str('%.4f' % cpuPercent) + +def getLoadavg(): + try: + loadavgstr = open('/proc/loadavg', 'r').readline().strip() + except IOError: + syslog.syslog(syslog.LOG_ERR, "failed to find cpu load") + return None + + data = map(float, loadavgstr.split()[1:]) + # returns 1 minute load average + return data[0] + + +def getInfinibandPortStatus(): + + """ Check for availability of infiniband port + and return which port is active in a key pair value + """ + + # Check for existence of infiniband ports + value = os.popen ("ls /sys/class/infiniband").readline().strip() + + if not value: + return None + + portlist = os.popen ("echo /sys/class/infiniband/*/ports/*").readline().split() + + portkeys = {} + + for port in portlist: + value = os.popen ("cat %s/state" % + port.strip()).readline().split(':')[1].strip() + portkeys[port.strip()] = value + + return portkeys + + +def getServerCount(): + try: + return int(open(Globals.SERVER_COUNT_FILE).read().strip()) + except IOError: + log("failed to read file %s" % Globals.SERVER_COUNT_FILE) + return 1 + except ValueError: + log("invalid number format in file %s" % Globals.SERVER_COUNT_FILE) + return 1 + + +def setServerCount(count): + try: + open(Globals.SERVER_COUNT_FILE, "w").write("%s\n" % count) + return True + except IOError: + log("failed to write file %s" % Globals.SERVER_COUNT_FILE) + return False + + +def getInstalledServerCount(): + try: + return int(open(Globals.INSTALLED_SERVER_COUNT_FILE).read().strip()) + except IOError: + log("failed to read file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return 1 + except ValueError: + log("invalid number format in file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return 1 + + +def setInstalledServerCount(count): + try: + open(Globals.INSTALLED_SERVER_COUNT_FILE, "w").write("%s\n" % count) + return True + except IOError: + log("failed to write file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return False + + +def getLastInstalledServerIpList(): + ipList = {} + networkDom = Protocol.XDOM() + if not networkDom.parseFile(Globals.GLOBAL_NETWORK_FILE): + log("failed to parse file %s" % Globals.GLOBAL_NETWORK_FILE) + for tagE in networkDom.getElementsByTagRoute("server.interface"): + interfaceDom = Protocol.XDOM() + interfaceDom.setDomObj(tagE) + ipAddress = interfaceDom.getTextByTagRoute("ipaddr") + if ipAddress: + ipList[interfaceDom.getTextByTagRoute("device")] = ipAddress + return ipList + + +def getFreeIpAddress(device=None): + serverCount = getServerCount() + installedServerCount = getInstalledServerCount() + if serverCount == installedServerCount: + return None + + availableServerCount = serverCount - installedServerCount + ipList = getLastInstalledServerIpList() + + if not ipList: + return None + + if device: + if device not in ipList.keys(): + return None + deviceIpAddress = ipList[device] + else: + deviceIpAddress = ipList.values()[0] + ipNumber = IP2Number(deviceIpAddress) + + for i in range((ipNumber + availableServerCount), ipNumber, -1): + ipAddress = Number2IP(i) + if runCommandFG(["ping", "-qnc", "1", ipAddress]) != 0: + return ipAddress + return None + + +def getPasswordHash(userName): + try: + #return spwd.getspnam(userName).sp_pwd + return "Not implimented" + except KeyError: + return None + + +def getTransactionKey(): + try: + tokens = open(Globals.TRANSACTION_KEY_FILE).read().split(',') + except IOError: + return None, None + return tokens + + +def generateSignature(): + #return str(uuid.uuid4()) + ('--%f' % time.time()) + return ('--%f' % time.time()) + + +def getSignature(): + try: + return open(Globals.SIGNATURE_FILE).read().strip() + except IOError: + log(syslog.LOG_ERR, "unable to read signaure from %s file" % Globals.SIGNATURE_FILE) + return False + + +def storeSignature(signature, fileName=Globals.SIGNATURE_FILE): + try: + open(fileName, "w").write(signature + "\n") + except IOError: + log(syslog.LOG_ERR, "unable to write signature %s to %s file" % (signature, fileName)) + return False + return True + + +def isUserExist(userName): + try: + grp.getgrnam(userName).gr_gid + return True + except KeyError: + pass + try: + pwd.getpwnam(userName).pw_uid + return True + except KeyError: + pass + return False + + +def getGsnUserInfo(fileName=Globals.GSN_USER_INFO_FILE): + userInfo = {} + userInfo["UserId"] = None + userInfo["Password"] = None + try: + for line in open(fileName): + line = line.strip() + k = line[:line.index("=")] + v = line[line.index("=") + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "GSN_ID": + userInfo["UserId"] = v + if k.upper() == "GSN_PASSWORD": + userInfo["Password"] = v + except IOError, e: + log("Failed to read file %s: %s" % (fileName, e)) + return userInfo + + +def setGsnUserInfo(userInfo, fileName=Globals.GSN_USER_INFO_FILE): + try: + fp = open(fileName, "w") + fp.write("GSN_ID=%s\n" % userInfo["UserId"]) + fp.write("GSN_PASSWORD=%s\n" % userInfo["Password"]) + fp.close() + return True + except IOError, e: + log("Failed to write file %s: %s" % (fileName, e)) + return False + + +def getPlatformVersion(fileName=Globals.GLUSTER_VERSION_FILE): + versionInfo = {} + versionInfo["Version"] = None + versionInfo["Update"] = None + try: + lines = open(Globals.GLUSTER_VERSION_FILE).readlines() + for line in open(fileName): + line = line.strip() + k = line[:line.index("=")] + v = line[line.index("=") + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "VERSION": + versionInfo["Version"] = v + if k.upper() == "UPDATE": + versionInfo["Update"] = v + except IOError, e: + log("Failed to read file %s: %s" % (fileName, e)) + return versionInfo + + +def setPlatformVersion(versionInfo, fileName=Globals.GLUSTER_VERSION_FILE): + if isString(versionInfo): + tokens = versionInfo.strip().split(".") + if len(tokens) < 2: + log("Invalid version format %s. Expecting <MAJOR>.<MINOR>.<PATCHLEVEL>" % versionInfo) + return False + version = ".".join(tokens[:2]) + update = ".".join(tokens[2:]) + if not update: + update = "0" + else: + version = versionInfo["Version"] + update = versionInfo["Update"] + try: + fp = open(fileName, "w") + fp.write("VERSION=%s\n" % version) + fp.write("UPDATE=%s\n" % update) + fp.close() + return True + except IOError, e: + log("Failed to write file %s: %s" % (fileName, e)) + return False + + +def getGlusterUpdateDom(serverVersion): + errorMessage = "" + updateInfoDom = None + try: + baseUrl = open(Globals.GLUSTER_UPDATE_SITE_FILE).read().strip() + except IOError, e: + log("Failed to read file %s: %s" % (Globals.GLUSTER_UPDATE_SITE_FILE, e)) + errorMessage = "Failed to read update site file" + return updateInfoDom, errorMessage + + try: + url = "%s/%s/%s" % (baseUrl, serverVersion, Globals.GLUSTER_UPDATES_FILE) + connection = urllib.urlopen(url) + if connection.getcode() != 200: + connection.close() + errorMessage = "Error received from server to open URL %s" % url + return updateInfoDom, errorMessage + updateInfoString = connection.read() + connection.close() + except IOError, e: + log("Failed to get update information from URL %s: %s" % (url, e)) + errorMessage = "Error getting update information" + return updateInfoDom, errorMessage + + updateInfoDom = Protocol.XDOM() + if not updateInfoDom.parseString(updateInfoString): + log("XML parse error on update information content [%s]" % updateInfoString) + errorMessage = "Parse error on update information" + updateInfoDom = None + return updateInfoDom, errorMessage + + +def removeFile(fileName, root=False): + if root: + if runCommand("rm %s" % fileName, root=True) == 0: + return True + return False + try: + os.remove(fileName) + return True + except OSError, e: + log("Failed to remove file %s: %s" % (fileName, e)) + return False + + +def isLiveMode(): + return os.path.exists(Globals.LIVE_MODE_FILE) + +def convertKbToMb(kb): + return kb / 1024.0 + + +def getIPIndex(indexFile): + try: + fp = open(indexFile) + line = fp.readline() + fp.close() + index = int(line) + except IOError: + index = 0 + except ValueError: + index = False + return index + +def setIPIndex(index, indexFile): + try: + fp = open(indexFile, "w") + fp.write(str(index)) + fp.close() + except IOError: + return False + return True + +def IP2Number(ipString): + try: + return socket.htonl(struct.unpack("I", socket.inet_aton(ipString))[0]) + except socket.error: + return None + except TypeError: + return None + except struct.error: + return None + +def Number2IP(number): + try: + return socket.inet_ntoa(struct.pack("I", socket.ntohl(number))) + except socket.error: + return None + except AttributeError: + return None + except ValueError: + return None + +def hasEntryFoundInFile(searchString, dnsEntryFileName): + try: + addServerEntryList = open(dnsEntryFileName).read().split() + except IOError: + return None + if searchString in addServerEntryList: + return True + return False + + +def computeIpAddress(ipAddress, startIp, endIp): + startIpNumber = IP2Number(startIp) + endIpNumber = IP2Number(endIp) + if not ipAddress: + return startIp + nextIpNumber = IP2Number(ipAddress) + while True: + nextIpNumber = nextIpNumber + 1 + ipAddress = Number2IP(nextIpNumber) + rv = runCommandFG(["ping", "-qnc", "1", ipAddress]) + if type(rv) == type(True): + return False + if rv != 0: + break + + if nextIpNumber >= startIpNumber and nextIpNumber <= endIpNumber: + return ipAddress + + nextIpNumber = IP2Number(startIp) + while True: + ipAddress = Number2IP(nextIpNumber) + nextIpNumber = nextIpNumber + 1 + rv = runCommandFG(["ping", "-qnc", "1", ipAddress]) + if type(rv) == type(True): + return False + if rv != 0: + break + + if IP2Number(ipAddress) >= startIpNumber and IP2Number(ipAddress) <= endIpNumber: + return ipAddress + return False + + +def setHostNameAndIp(hostName, ipAddress, lastAddServerDetailFile): + try: + fp = open(lastAddServerDetailFile, "w") + fp.write("HOSTNAME=" + hostName + "\n") + fp.write("IPADDRESS=" + ipAddress); + fp.close() + except IOError: + return False + return True + +def getPort(): + try: + fd = open(Globals.PORT_FILE, "r") + portString = fd.readline() + fd.close() + port = int(portString) + except IOError: + port = Globals.DEFAULT_PORT - 2 + except ValueError: + port = Globals.DEFAULT_PORT - 2 + return port + +def setPort(port): + try: + fd = open(Globals.PORT_FILE, "w") + fd.write(str(port)) + fd.close() + except IOError: + return False + return True + +def getServerAgentCredentials(): + try: + lines = open(Globals.SERVERAGENT_AUTH_FILE).readlines() + except IOError: + return None,None + + userName = None + password = None + + for l in lines: + if l[-1] == '\n': + l = l[:-1] + k = l[:l.index('=')] + v = l[l.index('=') + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "AGENT_ID": + userName = v + if k.upper() == "AGENT_PASSWORD": + password = v + + return userName, password + +def getGatewayAgentCredentials(): + try: + lines = open(Globals.GATEWAYAGENT_AUTH_FILE).readlines() + except IOError: + return None + + #userName = None + password = None + + for l in lines: + if l[-1] == '\n': + l = l[:-1] + k = l[:l.index('=')] + v = l[l.index('=') + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + #if k.upper() == "AGENT_ID": + # userName = v + if k.upper() == "AGENT_PASSWORD": + password = v + + return password + +def getWebAgentCredentials(): + try: + lines = open(Globals.WEBAGENT_AUTH_FILE).readlines() + except IOError: + return None,None + + userName = None + password = None + + for l in lines: + if l[-1] == '\n': + l = l[:-1] + k = l[:l.index('=')] + v = l[l.index('=') + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "AGENT_ID": + userName = v + if k.upper() == "AGENT_PASSWORD": + password = v + + return userName, password + +def daemonize(): + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file("/dev/null", 'r') + so = file("/dev/null", 'a+') + se = file("/dev/null", 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + return True + +def getFreeIpAddress(): + startRange, endRange = getStoragePoolInfo() + if not (startRange and endRange): + return None + + startIpNumber = IP2Number(startRange) + endIpNumber = IP2Number(endRange) + + for ipNumber in range(endIpNumber, startIpNumber, -1): + rv = runCommandFG(["ping", "-qnc", "1", Number2IP(ipNumber)]) + if type(rv) == type(True): + return None + if rv != 0: + return Number2IP(ipNumber) + return None + +def getDhcpServerStatus(): + status = runCommandFG(["sudo", "service", "dnsmasq", " status"]) + if type(status) == type(True) or 0 != status: + return False + return True + +def startDhcpServer(): + status = runCommandFG(["sudo", "service", "dnsmasq", " start"]) + if type(status) == type(True) or 0 != status: + return False + return True + +def stopDhcpServer(): + status = runCommandFG(["sudo", "service", "dnsmasq", " stop"]) + if type(status) == type(True) or 0 != status: + return False + return True + +def getStoragePoolInfo(): + startRange = None + endRange = None + try: + for line in open(Globals.GLUSTER_SERVER_POOL_FILE): + tokens = line.split("=") + if tokens[0] == "STARTRANGE": + startRange = tokens[1].strip() + if tokens[0] == "ENDRANGE": + endRange = tokens[1].strip() + except IOError: + log(syslog.LOG_ERR, "unable to read %s file" % Globals.GLUSTER_SERVER_POOL_FILE) + return startRange, endRange + +def configureDnsmasq(serverIpAddress, dhcpIpAddress): + dnsmasqConfFile = Globals.GLUSTER_CONF_CONF_DIR + "/dnsmasq.conf" + serverPortString = "68" + try: + for arg in open("/proc/cmdline").read().strip().split(): + token = arg.split("=") + if token[0] == "dhcp": + serverPortString = token[1] + break + except IOError: + log(syslog.LOG_ERR, "Failed to read /proc/cmdline. Continuing with default port 68") + try: + serverPort = int(serverPortString) + except ValueError: + log(syslog.LOG_ERR, "Invalid dhcp port '%s' in /proc/cmdline. Continuing with default port 68" % serverPortString) + serverPort = 68 + + try: + fp = open(dnsmasqConfFile, "w") + fp.write("no-hosts\n") + #fp.write("addn-hosts=%s\n" % Globals.GLUSTER_DNS_ENTRIES) + fp.write("bind-interfaces\n") + fp.write("except-interface=lo\n") + fp.write("dhcp-range=%s,%s\n" % (dhcpIpAddress, dhcpIpAddress)) + fp.write("dhcp-lease-max=1\n") + #fp.write("dhcp-option=option:router,%s\n" % serverIp) + #fp.write("dhcp-option=option:ntp-server,%s\n" % serverIp) + fp.write("dhcp-alternate-port=%s\n" % serverPort) + fp.write("server=%s\n" % serverIpAddress) + fp.write("dhcp-script=/usr/sbin/server-info\n") + fp.close() + except IOError: + log(syslog.LOG_ERR, "unable to write dnsmasq configuration %s" % dnsmasqConfFile) + return False + status = runCommandFG(["sudo", "cp", "-f", Globals.GLUSTER_CONF_CONF_DIR + "/dnsmasq.conf", Globals.DNSMASQ_CONF_FILE]) + if type(status) == type(True) or 0 != status: + log(syslog.LOG_ERR, "unable to copy dnsmasq configuration to " + Globals.DNSMASQ_CONF_FILE) + return False + return True + +def configureDhcpServer(serverIpAddress, dhcpIpAddress): + return configureDnsmasq(serverIpAddress, dhcpIpAddress) + +def log(priority, message=None): + if type(priority) == type(""): + logPriority = syslog.LOG_INFO + logMessage = priority + else: + logPriority = priority + logMessage = message + if not logMessage: + return + #if Globals.DEBUG: + # sys.stderr.write(logMessage) + else: + syslog.syslog(logPriority, logMessage) + return + + +def stripEmptyLines(content): + ret = "" + for line in content.split("\n"): + if line.strip() != "": + ret += line + return ret + + +def getDeviceFormatStatusFile(device): + return "/var/tmp/format_%s.status" % device.replace('/', '_') + +def getDeviceFormatLockFile(device): + return "/var/lock/format_%s.lock" % device.replace('/', '_') + +def getDeviceFormatOutputFile(device): + return "/var/tmp/format_%s.out" % device.replace('/', '_') diff --git a/src/com.gluster.storage.management.gateway.scripts/src/VolumeUtils.py b/src/com.gluster.storage.management.gateway.scripts/src/VolumeUtils.py new file mode 100644 index 00000000..b1031ccc --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/VolumeUtils.py @@ -0,0 +1,612 @@ +# 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) + return True + except OSError, e: + log("Failed to remove file %s: %s" % (volumeFile, str(e))) + return False + + +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.gateway.scripts/src/XmlHandler.py b/src/com.gluster.storage.management.gateway.scripts/src/XmlHandler.py new file mode 100644 index 00000000..72164ffb --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/XmlHandler.py @@ -0,0 +1,346 @@ +# Copyright (C) 2009 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 xml
+import xml.parsers.expat
+import xml.dom.minidom as MDOM
+import os
+import Globals
+import copy
+import Utils
+
+XML_STRING = 0
+XML_FILE = 1
+
+class XDOM:
+ _domObj = None
+
+ def __init__(self):
+ self._domObj = MDOM.Document()
+ return
+
+ @classmethod
+ def getText(self, nodeList):
+ rc = ""
+ for node in nodeList:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc
+
+ def parseString(self, requestString):
+ try:
+ self._domObj = MDOM.parseString(requestString)
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML string parse error: %s" % str(e))
+ return False
+ return True
+
+ def parseFile(self, fileName):
+ try:
+ self._domObj = MDOM.parse(fileName)
+ except IOError, e:
+ Utils.log("error reading file: %s" % str(e))
+ return False
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML file %s parse error: %s" % (fileName, str(e)))
+ return False
+ return True
+
+ def setDomObj(self, dom):
+ if dom and type(dom) != type([]):
+ self._domObj = dom
+ return True
+ return False
+
+ def createTag(self, tag, text=None):
+ if not self._domObj:
+ return None
+ if tag == None:
+ return None
+
+ tagE = self._domObj.createElement(str(tag))
+ if text:
+ tagEText = self._domObj.createTextNode(str(text))
+ tagE.appendChild(tagEText)
+ return tagE
+
+ def addTag(self, tag):
+ if not self._domObj:
+ return False
+ if not tag:
+ return False
+
+ self._domObj.appendChild(tag)
+ return True
+
+ def createTagRoute(self, tagRoute, text=None):
+ if not tagRoute:
+ return False
+
+ tagList = tagRoute.split(".")
+ tag = None
+ previousTag = None
+ for tagName in tagList[:-1]:
+ newTag = self.createTag(tagName, None)
+ if not tag:
+ tag = newTag
+ previousTag = newTag
+ continue
+ previousTag.appendChild(newTag)
+ previousTag = newTag
+
+ if previousTag:
+ previousTag.appendChild(self.createTag(tagList[-1], text))
+ else:
+ tag = self.createTag(tagList[-1], text)
+ return tag
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._domObj:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._domObj
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+
+ def setTextByTagRoute(self, tagRoute, tagValue):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ tagE = self.getElementsByTagRoute(tagRoute)
+ if not tagE:
+ return False
+
+ parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1]))
+ if not parentTagE:
+ return False
+
+ parentTagE[0].childNodes.remove(tagE[0])
+ parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue))
+ return True
+
+ def getElementsByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ x = None
+ for tag in tagRoute.split("."):
+ if x is None:
+ x = self._domObj.getElementsByTagName(tag)
+ continue
+ if x == []:
+ break
+ x = x[0].getElementsByTagName(tag)
+ return x
+
+ def getTextByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ x = self.getElementsByTagRoute(tagRoute)
+ if x:
+ return self.getText(x[0].childNodes)
+ return None
+
+ def getElementsByTagName(self, name):
+ if not self._domObj:
+ return None
+ return self._domObj.getElementsByTagName(name)
+
+ def writexml(self, fileName, indent="", addindent="", newl=""):
+ if not self._domObj:
+ return None
+ try:
+ fp = open(fileName, "w")
+ self._domObj.writexml(fp, indent, addindent, newl)
+ fp.close()
+ return True
+ except IOError:
+ return False
+
+ def toString(self, indent=" ", newl="\n", encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toprettyxml(indent, newl, encoding)
+
+ def toxml(self, encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toxml(encoding)
+
+ def toprettyxml(self, indent=" ", newl="\n", encoding = None):
+ return self.toString(indent, newl, encoding)
+
+ def createResponseTag(self):
+ responseTag = self._domObj.createElement("response")
+ return responseTag
+##--end of XDOM
+
+class RequestXml(XDOM):
+ def __init__(self, requestString, type=None):
+ if None == requestString:
+ XDOM.__init__(self)
+ return
+ try:
+ if None == type:
+ if os.path.isfile(requestString):
+ self._domObj = MDOM.parse(requestString)
+ else:
+ self._domObj = MDOM.parseString(requestString)
+ elif XML_FILE == type:
+ self._domObj = MDOM.parse(requestString)
+ elif XML_STRING == type:
+ self._domObj = MDOM.parseString(requestString)
+ except IOError:
+ XDOM.__init__(self)
+ except xml.parsers.expat.ExpatError:
+ XDOM.__init__(self)
+
+##--end of RequestXML
+
+
+class ResponseXml(XDOM):
+ _responseTag = None
+ def __init__(self):
+ XDOM.__init__(self)
+ self._responseTag = self.createResponseTag()
+ self._domObj.appendChild(self._responseTag)
+
+ @classmethod
+ def errorResponse(self, message):
+ if not self.responseTag:
+ return False
+ self.appendTagRoute("status.code", "-1");
+ self.appendTagRoute("status.message", message)
+
+ def append(self, tagName, tagValue=None):
+ if not self._responseTag:
+ return False
+ tag = self.createTag(tagName, tagValue)
+ if tag:
+ self._responseTag.appendChild(tag)
+ return True
+ return False
+
+ def appendTag(self, tag):
+ if not tag:
+ return False
+ if not self._responseTag:
+ return False
+ self._responseTag.appendChild(tag)
+ return True
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._responseTag:
+ return None
+ if not tagRoute:
+ return None
+
+ parentTagE = self._responseTag
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return None
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return None
+ return newTagE
+
+ def appendTagRouteOld(self, tagRoute, value=None):
+ if not self._responseTag:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._responseTag
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+##--end of ResponseXml
+
+def test():
+ rs = ResponseXml()
+ rs.appendTagRoute("status.code", "0");
+ rs.appendTagRoute("status.message", "SUCCESS")
+ serverTag = rs.appendTagRoute("server.name", "Server1")
+ networkInterfaces = rs.appendTagRoute("server.networkInterfaces", None)
+ networkTag = rs.createTag("networkInterface", None)
+ networkTag.appendChild(rs.createTag("name", "interface1"))
+ networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.40"))
+ networkInterfaces.appendChild(networkTag)
+ networkTag = rs.createTag("networkInterface", None)
+ networkTag.appendChild(rs.createTag("name", "interface2"))
+ networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.41"))
+ networkInterfaces.appendChild(networkTag)
+ print rs.toprettyxml()
+
+#test()
diff --git a/src/com.gluster.storage.management.gateway.scripts/src/add_user_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/add_user_cifs.py new file mode 100755 index 00000000..7b9650d1 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/add_user_cifs.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils + +def main(): + if len(sys.argv) < 4: + sys.stderr.write("usage: %s UID USERNAME PASSWORD\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + uid = sys.argv[1] + userName = sys.argv[2] + password = sys.argv[3] + + if Utils.runCommand("groupadd -g %s %s" % (uid, userName)) != 0: + Utils.log("failed to add group gid:%s, name:%s\n" % (uid, userName)) + sys.exit(1) + + command = ["useradd", "-c", Globals.VOLUME_USER_DESCRIPTION, "-M", "-d", "/", "-s", "/sbin/nologin", "-u", uid, "-g", uid, userName] + if Utils.runCommand(command) != 0: + Utils.log("failed to add user uid:%s, name:%s\n" % (uid, userName)) + sys.exit(2) + + if Utils.runCommand("smbpasswd -s -a %s" % userName, + input="%s\n%s\n" % (password, password)) != 0: + Utils.log("failed to set smbpassword of user uid:%s, name:%s\n" % (uid, userName)) + sys.exit(3) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/clear_volume_directory.py b/src/com.gluster.storage.management.gateway.scripts/src/clear_volume_directory.py new file mode 100755 index 00000000..96677f56 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/clear_volume_directory.py @@ -0,0 +1,97 @@ +#!/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 sys +import syslog +import time +from XmlHandler import ResponseXml +import DiskUtils +import Utils +from optparse import OptionParser + +def clearVolumeDirectory(diskMountPoint, volumeName, todelete): + rs = ResponseXml() + if not DiskUtils.checkDiskMountPoint(diskMountPoint): + Utils.log("failed to find disk mount point %s" % diskMountPoint) + rs.appendTagRoute("status.code", "-1") + rs.appendTagRoute("status.message", "Error: Mount point does not exists") + return rs.toprettyxml() + + if not os.path.exists(diskMountPoint): + rs.appendTagRoute("status.code", "-2") + rs.appendTagRoute("status.message", "Error: Mount point path does not exists") + return rs.toprettyxml() + + # clear volume directory from the disk + volumeDirectory = "%s/%s" % (diskMountPoint, volumeName) + if not os.path.exists(volumeDirectory): + rs.appendTagRoute("status.code", "-3") + rs.appendTagRoute("status.message", "Error: Volume directory does not exists") + return rs.toprettyxml() + + newVolumeDirectoryName = "%s_%s" % (volumeDirectory, time.time()) + command = ["sudo", "mv", "-f", volumeDirectory, newVolumeDirectoryName] + rv = Utils.runCommandFG(command, stdout=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to rename volume directory %s, %s" % (volumeDirectory, error)) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + + if not todelete: + rv["Status"] = "0" + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + + command = ["sudo", "rm", "-fr", newVolumeDirectoryName] + rv = Utils.runCommandFG(command, stdout=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to clear volume directory %s, %s" % (newVolumeDirectoryName, error)) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + + if not rv["Status"]: + rv["Status"] = "0" + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + +def main(): + parser = OptionParser() + parser.add_option("-d", "--delete", dest="deletedir", action="store_true", default=False, help="force delete") + (options, args) = parser.parse_args() + + if len(args) != 2: + sys.stderr.write("usage: %s <disk mount point> <volume name> [-d/--delete]\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + diskMountPoint = args[0] + volumeName = args[1] + print clearVolumeDirectory(diskMountPoint, volumeName, options.deletedir) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/create_volume_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/create_volume_cifs.py new file mode 100755 index 00000000..a81b165b --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/create_volume_cifs.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils +import VolumeUtils + +def main(): + if len(sys.argv) < 3: + sys.stderr.write("usage: %s VOLUME_NAME USER1 USER2 ...\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + userList = sys.argv[2:] + + volumeMountDirName = "%s/%s" % (Globals.REEXPORT_DIR, volumeName) + try: + os.mkdir(volumeMountDirName) + except OSError, e: + Utils.log("failed creating %s: %s\n" % (volumeMountDirName, str(e))) + sys.exit(1) + + if VolumeUtils.writeVolumeCifsConfiguration(volumeName, userList): + sys.exit(0) + sys.exit(2) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/create_volume_directory.py b/src/com.gluster.storage.management.gateway.scripts/src/create_volume_directory.py new file mode 100755 index 00000000..3e633697 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/create_volume_directory.py @@ -0,0 +1,82 @@ +#!/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 sys +from XmlHandler import ResponseXml +import DiskUtils +import Utils + +def createDirectory(disk, volumeName): + # Retrieving disk uuid + diskUuid = DiskUtils.getUuidByDiskPartition(DiskUtils.getDevice(disk)) + + rs = ResponseXml() + if not diskUuid: + Utils.log("failed to find disk:%s uuid" % disk) + rs.appendTagRoute("status.code", "-1") + rs.appendTagRoute("status.message", "Error: Unable to find disk uuid") + return rs.toprettyxml() + + # Retrieving disk mount point using disk uuid + diskMountPoint = DiskUtils.getMountPointByUuid(diskUuid) + if not os.path.exists(diskMountPoint): + Utils.log("failed to retrieve disk:%s mount point" % disk) + rs.appendTagRoute("status.code", "-1") + rs.appendTagRoute("status.message", "Error: Failed to retrieve disk details") + return rs.toprettyxml() + + # creating volume directory under disk mount point + volumeDirectory = "%s/%s" % (diskMountPoint, volumeName) + if os.path.exists(volumeDirectory): + Utils.log("Volume directory:%s already exists" % (volumeDirectory)) + rs.appendTagRoute("status.code", "-2") + rs.appendTagRoute("status.message", "Volume directory already exists!") + return rs.toprettyxml() + + if not os.path.exists(volumeDirectory): + command = ["sudo", "mkdir", volumeDirectory] + rv = Utils.runCommandFG(command, stdout=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to create volume directory %s, %s" % (volumeDirectory, error)) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + + if not rv["Status"]: + rv["Status"] = "0" + if rv["Status"] == "0": + message = volumeDirectory + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toprettyxml() + +def main(): + if len(sys.argv) != 3: + sys.stderr.write("usage: %s <disk name> <volume name>\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + disk = sys.argv[1] + volumeName = sys.argv[2] + print createDirectory(disk, volumeName) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/delete_user_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/delete_user_cifs.py new file mode 100755 index 00000000..e5cda957 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/delete_user_cifs.py @@ -0,0 +1,24 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Utils + +def main(): + if len(sys.argv) < 2: + sys.stderr.write("usage: %s USERNAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + userName = sys.argv[1] + + if Utils.runCommand("userdel %s" % userName) != 0: + Utils.log("failed to remove user name:%s\n" % userName) + sys.exit(1) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/delete_volume_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/delete_volume_cifs.py new file mode 100755 index 00000000..fd1febc9 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/delete_volume_cifs.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils +import VolumeUtils + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s VOLUME_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + + volumeMountDirName = "%s/%s" % (Globals.REEXPORT_DIR, volumeName) + try: + os.rmdir(volumeMountDirName) + except OSError, e: + Utils.log("failed deleting %s: %s\n" % (volumeMountDirName, str(e))) + sys.exit(1) + + if VolumeUtils.removeVolumeCifsConfiguration(volumeName): + sys.exit(0) + sys.exit(2) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/disable-ssh-password-auth.sh b/src/com.gluster.storage.management.gateway.scripts/src/disable-ssh-password-auth.sh new file mode 100755 index 00000000..07ee1a3a --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/disable-ssh-password-auth.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +#----------------------------------------------------------------------------- +# disable-ssh-password-auth.sh +# Script for disabling SSH password authentication. This is used by the +# management gateway after installing the public key, so that the gluster +# node can be accessed (using ssh) only from the management gateway. +#----------------------------------------------------------------------------- + +CONFIG_FILE="/etc/ssh/sshd_config" +TIMESTAMP=`date +%d%m%Y%H%M%S` +BACKUP_FILE="${CONFIG_FILE}_${TIMESTAMP}" +TEMP_FILE="/tmp/new_sshd_config_${TIMESTAMP}" + +# Modify config file to disable password authentication, redirect to a temp file +# TODO: disable only if enabled! +sed "s/^PasswordAuthentication yes$/PasswordAuthentication no/g" ${CONFIG_FILE} > ${TEMP_FILE} + +# Secure the file by changing permissions (600) +chmod 600 ${TEMP_FILE} + +# Take backup of config file +cp ${CONFIG_FILE} ${BACKUP_FILE} + +# Overwrite config file with the modified one +mv ${TEMP_FILE} ${CONFIG_FILE} + +# Re-start ssh daemon +/etc/init.d/sshd restart + diff --git a/src/com.gluster.storage.management.gateway.scripts/src/format_device.py b/src/com.gluster.storage.management.gateway.scripts/src/format_device.py new file mode 100755 index 00000000..3bc70532 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/format_device.py @@ -0,0 +1,87 @@ +#!/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 sys +import Globals +import Utils +import DiskUtils +from optparse import OptionParser + + +def main(): + if Utils.runCommand("wget -q -O /dev/null %s" % Globals.AWS_WEB_SERVICE_URL) == 0: + sys.stderr.write("format device unsupported") + sys.exit(1) + + parser = OptionParser() + parser.add_option("-t", "--type", action="store", type="string", dest="fstype") + (options, args) = parser.parse_args() + + if len(args) != 1: + sys.stderr.write("usage: %s [-t FSTYPE] DEVICE_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + device = DiskUtils.getDevice(args[0]) + deviceFormatLockFile = Utils.getDeviceFormatLockFile(device) + deviceFormatStatusFile = Utils.getDeviceFormatStatusFile(device) + deviceFormatOutputFile = Utils.getDeviceFormatOutputFile(device) + + if DiskUtils.isDataDiskPartitionFormatted(device): + sys.stderr.write("Device already formatted\n") + sys.exit(2) + + if os.path.exists(deviceFormatStatusFile): + Utils.log("format status file %s exists" % deviceFormatStatusFile) + try: + fp = open(deviceFormatStatusFile) + line = fp.read() + fp.close() + if line.strip().upper() == "COMPLETED": + sys.stderr.write("Device already formatted\n") + sys.exit(3) + else: + sys.stderr.write("Device format already running\n") + sys.exit(4) + except IOError, e: + Utils.log("failed to read format status file %s: %s" % (deviceFormatStatusFile, str(e))) + sys.stderr.write("%s\n" % str(e)) + sys.exit(-2) + + if os.path.exists(deviceFormatLockFile): + Utils.log("lock file %s exists" % deviceFormatLockFile) + sys.stderr.write("Device format already running\n") + sys.exit(5) + + if options.fstype: + command = ["gluster_provision_block_wrapper.py", "-t", "%s" % (options.fstype), "%s" % (device)] + else: + command = ["gluster_provision_block_wrapper.py", "%s" % (device)] + + try: + pid = os.fork() + except OSError, e: + Utils.log("failed to fork a child process: %s" % str(e)) + sys.exit(6) + if pid == 0: + os.execv("/usr/sbin/gluster_provision_block_wrapper.py", command) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_brick_status.py b/src/com.gluster.storage.management.gateway.scripts/src/get_brick_status.py new file mode 100755 index 00000000..cf84080b --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_brick_status.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Console. +# + +import os +import sys +import Utils + +def main(): + if len(sys.argv) != 3: + sys.stderr.write("usage: %s VOLUME_NAME BRICK_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + brickName = sys.argv[2] + pidFile = "/etc/glusterd/vols/%s/run/%s.pid" % (volumeName, brickName.replace(":", "").replace("/", "-")) + + if not os.path.exists(pidFile): + print "OFFLINE" + else: + try: + fp = open(pidFile) + pidString = fp.readline() + fp.close() + os.getpgid(int(pidString)) + print "ONLINE" + except IOError, e: + Utils.log("failed to open file %s: %s" % (pidFile, str(e))) + print "UNKNOWN" + except ValueError, e: + Utils.log("invalid pid %s in file %s: %s" % (pidString, pidFile, str(e))) + print "UNKNOWN" + except OSError, e: + #Utils.log("failed to get process detail of pid %s: %s" % (pidString, str(e))) + print "OFFLINE" + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_disk_mount_point.py b/src/com.gluster.storage.management.gateway.scripts/src/get_disk_mount_point.py new file mode 100755 index 00000000..2f4a39c3 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_disk_mount_point.py @@ -0,0 +1,62 @@ +#!/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 Utils +from DiskUtils import * +from XmlHandler import ResponseXml + + +def getmountpoint(path): + if not path: + Utils.log("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 + + for line in readFsTab(): + if path.startswith(line['MountPoint']): + if not mountPoint: + mountPoint = line['MountPoint'] + if len(line['MountPoint']) > len(mountPoint): + mountPoint = line['MountPoint'] + + if "/" == mountPoint or not mountPoint: + Utils.log("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") + rs.appendTagRoute("status.message", mountPoint) + return rs.toprettyxml() + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s <path>\n" % os.path.basename(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.gateway.scripts/src/get_disk_name_by_path.py b/src/com.gluster.storage.management.gateway.scripts/src/get_disk_name_by_path.py new file mode 100755 index 00000000..08e80b7e --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_disk_name_by_path.py @@ -0,0 +1,68 @@ +#!/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 Utils +from DiskUtils import * +from XmlHandler import ResponseXml + + +def getmountpoint(path): + if not path: + Utils.log("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: + Utils.log("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: + sys.stderr.write("usage: %s <path>\n" % os.path.basename(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.gateway.scripts/src/get_file.py b/src/com.gluster.storage.management.gateway.scripts/src/get_file.py new file mode 100755 index 00000000..61c33eba --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_file.py @@ -0,0 +1,130 @@ +# 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 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.gateway.scripts/src/get_format_device_status.py b/src/com.gluster.storage.management.gateway.scripts/src/get_format_device_status.py new file mode 100755 index 00000000..57fc0455 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_format_device_status.py @@ -0,0 +1,124 @@ +#!/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 os +import sys +import time +import Utils +import DiskUtils +from XmlHandler import ResponseXml + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s DEVICE_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + device = DiskUtils.getDevice(sys.argv[1]) + + deviceFormatLockFile = Utils.getDeviceFormatLockFile(device) + deviceFormatStatusFile = Utils.getDeviceFormatStatusFile(device) + deviceFormatOutputFile = Utils.getDeviceFormatOutputFile(device) + + time.sleep(1) + if not os.path.exists(deviceFormatLockFile): + if not os.path.exists(deviceFormatStatusFile): + sys.stderr.write("Device format not initiated\n") + sys.exit(1) + + if os.path.exists(deviceFormatStatusFile): + try: + fp = open(deviceFormatStatusFile) + line = fp.read() + fp.close() + line = line.strip() + + Utils.removeFile(deviceFormatOutputFile) + Utils.removeFile(deviceFormatStatusFile) + + responseDom = ResponseXml() + responseDom.appendTagRoute("device", sys.argv[1]) + responseDom.appendTagRoute("completedBlocks", "0") + responseDom.appendTagRoute("totalBlocks", "0") + responseDom.appendTagRoute("message", line) + if line.upper() == "COMPLETED": + responseDom.appendTagRoute("formatStatus", "COMPLETED") + else: + responseDom.appendTagRoute("formatStatus", "NOT_RUNNING") + print responseDom.toxml() + sys.exit(0) + except IOError, e: + Utils.log("failed to read format status file %s: %s" % (deviceFormatStatusFile, str(e))) + sys.stderr.write("%s\n" % str(e)) + sys.exit(-2) + + if not os.path.exists(deviceFormatOutputFile): + responseDom = ResponseXml() + responseDom.appendTagRoute("device", sys.argv[1]) + responseDom.appendTagRoute("completedBlocks", "0") + responseDom.appendTagRoute("totalBlocks", "0") + responseDom.appendTagRoute("message", None) + responseDom.appendTagRoute("formatStatus", "IN_PROGRESS") + print responseDom.toxml() + sys.exit(0) + + try: + fp = open(deviceFormatOutputFile) + content = fp.read() + fp.close() + except IOError, e: + Utils.log("failed to read format output file %s: %s" % (deviceFormatOutputFile, str(e))) + responseDom = ResponseXml() + responseDom.appendTagRoute("device", sys.argv[1]) + responseDom.appendTagRoute("completedBlocks", "0") + responseDom.appendTagRoute("totalBlocks", "0") + responseDom.appendTagRoute("message", None) + responseDom.appendTagRoute("formatStatus", "IN_PROGRESS") + print responseDom.toxml() + sys.exit(0) + + lines = [line for line in content + if "Writing inode tables" in line] + if not lines: + responseDom = ResponseXml() + responseDom.appendTagRoute("device", sys.argv[1]) + responseDom.appendTagRoute("completedBlocks", "0") + responseDom.appendTagRoute("totalBlocks", "0") + if content: + responseDom.appendTagRoute("message", content[-1]) + else: + responseDom.appendTagRoute("message") + responseDom.appendTagRoute("formatStatus", "IN_PROGRESS") + print responseDom.toxml() + sys.exit(0) + + tokens = [token for token in lines[-1].split("\x08") if token] + if "done" in tokens[-1]: + values = tokens[-2].split(':')[-1].strip().split('/') + else: + values = tokens[-1].split(':')[-1].strip().split('/') + + responseDom.appendTagRoute("device", sys.argv[1]) + responseDom.appendTagRoute("completedBlocks", values[0]) + responseDom.appendTagRoute("totalBlocks", values[1]) + responseDom.appendTagRoute("message", lines[-1]) + responseDom.appendTagRoute("formatStatus", "IN_PROGRESS") + print responseDom.toxml() + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_cpu_details.py b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_cpu_details.py new file mode 100755 index 00000000..546aec31 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_cpu_details.py @@ -0,0 +1,55 @@ +#!/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 sys +from XmlHandler import ResponseXml +import Utils + +def getCpuData(period): + cpuRrdFile = "/var/lib/rrd/cpu.rrd" + rs = ResponseXml() + command = "rrdtool xport --start -%s \ + DEF:cpuuser=%s:user:AVERAGE \ + DEF:cpusystem=%s:system:AVERAGE \ + CDEF:total=cpuuser,cpusystem,+ \ + XPORT:cpuuser:user \ + XPORT:cpusystem:system \ + XPORT:total:total" % (period, cpuRrdFile, cpuRrdFile) + + rv = Utils.runCommand(command, output=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to create RRD file for cpu usages %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return rv["Stdout"] + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s <period>\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + period = sys.argv[1] + print getCpuData(period) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_memory_details.py b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_memory_details.py new file mode 100755 index 00000000..f7c3031b --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_memory_details.py @@ -0,0 +1,89 @@ +#!/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/>. + +# Input command: get_rrd_memory_details.py 1hour +# OUTPUT as bellow: +# <?xml version="1.0" encoding="ISO-8859-1"?> +# +# <xport> +# <meta> +# <start>1310455500</start> +# <step>300</step> +# <end>1310459100</end> +# <rows>13</rows> +# <columns>5</columns> +# <legend> +# <entry>memoryUsed</entry> +# <entry>memoryFree</entry> +# <entry>memoryCache</entry> +# <entry>memoryBuffer</entry> +# <entry>totalMemory</entry> +# </legend> +# </meta> +# <data> +# <row><t>1310455500</t><v>1.9181091707e+06</v><v>1.5819754974e+06</v><v>1.2528146351e+06</v><v>1.2528146351e+06</v><v>3.5000846681e+06</v></row> +# --- +# --- +# </data> +# </xport> + +import os +import sys +import syslog +from XmlHandler import ResponseXml +import Utils + +def getMemData(period): + memRrdFile = "/var/lib/rrd/mem.rrd" + rs = ResponseXml() + command = "rrdtool xport --start -%s \ + DEF:free=%s:memfree:AVERAGE \ + DEF:used=%s:memused:AVERAGE \ + DEF:cache=%s:memcache:AVERAGE \ + DEF:buffer=%s:membuffer:AVERAGE \ + CDEF:total1=used,free,+ \ + CDEF:used1=used,buffer,cache,-,- \ + CDEF:total=total1,used1,+ \ + XPORT:used:memoryUsed \ + XPORT:free:memoryFree \ + XPORT:cache:memoryCache \ + XPORT:buffer:memoryBuffer \ + XPORT:total:totalMemory" % (period, memRrdFile, memRrdFile, memRrdFile, memRrdFile) + + rv = Utils.runCommand(command, output=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to create RRD file for memory usages %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return rv["Stdout"] + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s <period>\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + period = sys.argv[1] + print getMemData(period) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_net_details.py b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_net_details.py new file mode 100755 index 00000000..6a31cde8 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_rrd_net_details.py @@ -0,0 +1,52 @@ +#!/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 sys +from XmlHandler import ResponseXml +import Utils + +def main(): + if len(sys.argv) != 3: + sys.stderr.write("usage: %s <DEVICE> <PERIOD>\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + device = sys.argv[1] + period = sys.argv[2] + + rs = ResponseXml() + command = "rrdtool xport --start -%s \ + DEF:received=/var/lib/rrd/network-%s.rrd:received:AVERAGE \ + DEF:transmitted=/var/lib/rrd/network-%s.rrd:transmitted:AVERAGE \ + CDEF:total=received,transmitted,+ \ + XPORT:received:received \ + XPORT:transmitted:transmitted \ + XPORT:total:total" % (period, device, device) + rv = Utils.runCommand(command, output=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to get RRD information of device %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + print rs.toxml() + print rv["Stdout"] + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_server_details.py b/src/com.gluster.storage.management.gateway.scripts/src/get_server_details.py new file mode 100755 index 00000000..9c3da741 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_server_details.py @@ -0,0 +1,118 @@ +#!/usr/bin/python +# Copyright (C) 2009 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 sys +import socket +import re +import Utils +import DiskUtils +from NetworkUtils import * +from Disk import * +from XmlHandler import ResponseXml +from optparse import OptionParser + + +def getServerDetails(listall): + serverName = socket.gethostname() + meminfo = getMeminfo() + cpu = getCpuUsageAvg() + nameServerList, domain, searchDomain = readResolvConfFile() + if not domain: + domain = [None] + + responseDom = ResponseXml() + serverTag = responseDom.appendTagRoute("server") + serverTag.appendChild(responseDom.createTag("name", serverName)) + serverTag.appendChild(responseDom.createTag("domainname", domain[0])) + if Utils.runCommand("pidof glusterd") == 0: + serverTag.appendChild(responseDom.createTag("status", "ONLINE")) + else: + serverTag.appendChild(responseDom.createTag("status", "OFFLINE")) + serverTag.appendChild(responseDom.createTag("cpuUsage", str(cpu))) + serverTag.appendChild(responseDom.createTag("totalMemory", str(convertKbToMb(meminfo['MemTotal'])))) + serverTag.appendChild(responseDom.createTag("memoryInUse", str(convertKbToMb(meminfo['MemUsed'])))) + serverTag.appendChild(responseDom.createTag("uuid", None)) + + for dns in nameServerList: + serverTag.appendChild(responseDom.createTag("dns%s" % str(nameServerList.index(dns) +1) , dns)) + + #TODO: probe and retrieve timezone, ntp-server details and update the tags + + deviceList = {} + interfaces = responseDom.createTag("networkInterfaces", None) + for device in getNetDeviceList(): + if device["model"] in ['LOCAL', 'IPV6-IN-IPV4']: + continue + deviceList[device["device"]] = device + try: + macAddress = open("/sys/class/net/%s/address" % device["device"]).read().strip() + except IOError: + continue + interfaceTag = responseDom.createTag("networkInterface", None) + interfaceTag.appendChild(responseDom.createTag("name", device["device"])) + interfaceTag.appendChild(responseDom.createTag("hwAddr",macAddress)) + interfaceTag.appendChild(responseDom.createTag("speed", device["speed"])) + interfaceTag.appendChild(responseDom.createTag("model", device["model"])) + if deviceList[device["device"]]: + if deviceList[device["device"]]["onboot"]: + interfaceTag.appendChild(responseDom.createTag("onboot", "yes")) + else: + interfaceTag.appendChild(responseDom.createTag("onBoot", "no")) + interfaceTag.appendChild(responseDom.createTag("bootProto", deviceList[device["device"]]["bootproto"])) + interfaceTag.appendChild(responseDom.createTag("ipAddress", deviceList[device["device"]]["ipaddr"])) + interfaceTag.appendChild(responseDom.createTag("netMask", deviceList[device["device"]]["netmask"])) + interfaceTag.appendChild(responseDom.createTag("defaultGateway", deviceList[device["device"]]["gateway"])) + if deviceList[device["device"]]["mode"]: + interfaceTag.appendChild(responseDom.createTag("mode", deviceList[device["device"]]["mode"])) + if deviceList[device["device"]]["master"]: + interfaceTag.appendChild(responseDom.createTag("bonding", "yes")) + spliter = re.compile(r'[\D]') + interfaceTag.appendChild(responseDom.createTag("bondid", spliter.split(device["master"])[-1])) + else: + interfaceTag.appendChild(responseDom.createTag("onBoot", "no")) + interfaceTag.appendChild(responseDom.createTag("bootProto", "none")) + interfaces.appendChild(interfaceTag) + serverTag.appendChild(interfaces) + + responseDom.appendTag(serverTag) + serverTag.appendChild(responseDom.createTag("numOfCPUs", int(os.sysconf('SC_NPROCESSORS_ONLN')))) + + diskDom = DiskUtils.getDiskDom() + if not diskDom: + sys.stderr.write("No disk found!") + Utils.log("Failed to get disk details") + sys.exit(1) + + serverTag.appendChild(diskDom.getElementsByTagRoute("disks")[0]) + return serverTag + +def main(): + parser = OptionParser() + parser.add_option("-N", "--only-data-disks", + action="store_false", dest="listall", default=True, + help="List only data disks") + + (options, args) = parser.parse_args() + responseXml = getServerDetails(options.listall) + if responseXml: + print responseXml.toxml() + + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_server_status.py b/src/com.gluster.storage.management.gateway.scripts/src/get_server_status.py new file mode 100755 index 00000000..a57428b6 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_server_status.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Console. +# + +import os +import sys +import Utils + +def main(): + if len(sys.argv) != 1: + sys.stderr.write("usage: %s\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + if Utils.runCommand("pidof glusterd") == 0: + print "ONLINE" + else: + print "OFFLINE" + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/get_volume_brick_log.py b/src/com.gluster.storage.management.gateway.scripts/src/get_volume_brick_log.py new file mode 100755 index 00000000..fd7361da --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_volume_brick_log.py @@ -0,0 +1,103 @@ +#!/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 XDOM + +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, logMessagesTag, loginfo): + logMessageTag = responseDom.createTag("logMessage") + logMessageTag.appendChild(responseDom.createTag("timestamp", loginfo[0] + " " + loginfo[1])) + logMessageTag.appendChild(responseDom.createTag("severity", enumLogType(loginfo[2]))) + logMessageTag.appendChild(responseDom.createTag("message", loginfo[3])) + logMessagesTag.appendChild(logMessageTag); + 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 = XDOM() + if not logFilePath: + print >> sys.stderr, "No log file path given" + sys.exit(-1); + + if not tailCount: + print >> sys.stderr, "No tail count given" + sys.exit(-1); + + pattern = '\[\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}.\d+\]\s{1}([MACEWNIDT]){1}\s+' + if not os.path.exists(logFilePath): + print >> sys.stderr, "volume log file [%s] not found!" % logFilePath + sys.exit(-1); + + fp = open(logFilePath) + lines = [line for line in fp if re.match(pattern, line)] + fp.close() + i = len(lines) - int(tailCount) + if i < 0: + i = 0 + logMessagesTag = rs.createTag("logMessages") + rs.addTag(logMessagesTag) + for log in lines[i:]: + loginfo = logSplit(log) + addLog(rs, logMessagesTag, loginfo) + return rs.toxml() +##--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.gateway.scripts/src/get_volume_log.py b/src/com.gluster.storage.management.gateway.scripts/src/get_volume_log.py new file mode 100755 index 00000000..b906c002 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/get_volume_log.py @@ -0,0 +1,131 @@ +# 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 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.gateway.scripts/src/gluster_provision_block_wrapper.py b/src/com.gluster.storage.management.gateway.scripts/src/gluster_provision_block_wrapper.py new file mode 100755 index 00000000..a3b2776d --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/gluster_provision_block_wrapper.py @@ -0,0 +1,109 @@ +#!/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 sys +import subprocess +import Utils +import DiskUtils +from optparse import OptionParser + +def writeStatus(deviceFormatStatusFile, message): + try: + fp = open(deviceFormatStatusFile, "w") + fp.write(message) + fp.close() + except IOError, e: + Utils.log("Failed to update log file %s: %s" % (deviceFormatStatusFile, str(e))) + return False + return True + + +def main(): + parser = OptionParser() + parser.add_option("-t", "--type", action="store", type="string", dest="fstype") + (options, args) = parser.parse_args() + + if len(args) != 1: + sys.stderr.write("usage: %s [-t FSTYPE] DEVICE" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + device = args[0] + deviceFormatLockFile = Utils.getDeviceFormatLockFile(device) + deviceFormatStatusFile = Utils.getDeviceFormatStatusFile(device) + deviceFormatOutputFile = Utils.getDeviceFormatOutputFile(device) + + if os.path.exists(deviceFormatStatusFile): + Utils.log("device format status file %s exists" % deviceFormatStatusFile) + sys.exit(1) + + if os.path.exists(deviceFormatLockFile): + Utils.log("device format lock file %s exists" % deviceFormatLockFile) + sys.exit(2) + + try: + fp = open(deviceFormatLockFile, "w") + fp.close() + except OSError, e: + Utils.log("failed to create lock file %s: %s" % (deviceFormatLockFile, str(e))) + writeStatus(deviceFormatStatusFile, "Lock file creation failed\n") + sys.exit(3) + + try: + fptr = open(deviceFormatOutputFile, 'w') + except IOError, e: + Utils.log("failed to create output file %s" % deviceFormatOutputFile) + writeStatus(deviceFormatStatusFile, "Output file creation failed\n") + Utils.removeFile(deviceFormatLockFile) + sys.exit(4) + + if options.fstype: + command = "gluster-provision-block -t %s %s" % (options.fstype, device) + else: + command = "gluster-provision-block %s" % (device) + + process = Utils.runCommandBG(command, + stdinFileObj=subprocess.PIPE, + stdoutFileObj=fptr, + stderrFileObj=subprocess.PIPE) + if process: + status = process.wait() + else: + Utils.removeFile(deviceFormatOutputFile) + Utils.removeFile(deviceFormatLockFile) + writeStatus(deviceFormatStatusFile, "Device format failed\n") + sys.exit(5) + + if status != 0: + Utils.removeFile(deviceFormatOutputFile) + Utils.removeFile(deviceFormatLockFile) + writeStatus(deviceFormatStatusFile, "Device format failed\n") + sys.exit(6) + + if Utils.runCommand("/sbin/udevtrigger") != 0: + Utils.log("failed running /sbin/udevtrigger") + + if Utils.runCommand("/usr/bin/lshal") != 0: + Utils.log("failed running /usr/bin/lshal") + writeStatus(deviceFormatStatusFile, "Completed\n") + Utils.removeFile(deviceFormatOutputFile) + Utils.removeFile(deviceFormatLockFile) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/modify_volume_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/modify_volume_cifs.py new file mode 100755 index 00000000..f6bacfc4 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/modify_volume_cifs.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Utils +import VolumeUtils + +def main(): + if len(sys.argv) <= 2: + sys.stderr.write("usage: %s VOLUME_NAME USER1 USER2 ...\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + userList = sys.argv[2:] + + if not VolumeUtils.writeVolumeCifsConfiguration(volumeName, userList): + sys.exit(1) + if Utils.runCommand("service smb reload") != 0: + Utils.log("Failed to reload smb service") + sys.exit(2) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/multicast_response.py b/src/com.gluster.storage.management.gateway.scripts/src/multicast_response.py new file mode 100644 index 00000000..18cf89ae --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/multicast_response.py @@ -0,0 +1,74 @@ +#!/usr/bin/python
+# Copyright (C) 2009 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 string
+import time
+import Utils
+import socket
+import struct
+import Globals
+from XmlHandler import *
+
+def isInPeer():
+ command = "gluster peer status"
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ if status["Stdout"].strip().upper() != "NO PEERS PRESENT":
+ return True
+ return False
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+def response(multiCastGroup, port):
+ # waiting for the request!
+ socketRequest = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketRequest.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ socketRequest.bind(('', port))
+ mreq = struct.pack("4sl", socket.inet_aton(multiCastGroup), socket.INADDR_ANY)
+ socketRequest.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+
+ socketSend = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketSend.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
+
+ #TODO: Remove infinite loop and make this as a deamon (service)
+ while True:
+ request = socketRequest.recvfrom(1024)
+ if not request:
+ continue
+ dom = XDOM()
+ dom.parseString(request[0])
+ if not dom:
+ continue
+ if not dom.getTextByTagRoute("request.name"):
+ continue
+ requesttime = dom.getTextByTagRoute("request.time")
+ if not requesttime:
+ continue
+ if isInPeer():
+ time.sleep(5)
+ continue
+ socketSend.sendto("<response><servername>%s</servername><time>%s</time></response>" % (socket.gethostname(), requesttime),
+ (multiCastGroup, port))
+ request = None
+
+def main():
+ response(Globals.MULTICAST_GROUP, Globals.MULTICAST_PORT)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.gateway.scripts/src/rrd_cpu.pl b/src/com.gluster.storage.management.gateway.scripts/src/rrd_cpu.pl new file mode 100755 index 00000000..7b070812 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/rrd_cpu.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl + +use RRDs; + +my $rrdlog = '/var/lib/rrd'; +my $graphs = '/var/lib/rrd'; + +updatecpudata(); +#updatecpugraph('day'); +#updatecpugraph('week'); +#updatecpugraph('month'); +#updatecpugraph('year'); + +sub updatecpugraph { + my $period = $_[0]; + + RRDs::graph ("$graphs/cpu-$period.png", + "--start", "-1$period", "-aPNG", "-i", "-z", + "--alt-y-grid", "-w 300", "-h 50", "-l 0", "-u 100", "-r", + "--color", "SHADEA#FFFFFF", + "--color", "SHADEB#FFFFFF", + "--color", "BACK#FFFFFF", + "-t cpu usage per $period", + "DEF:user=$rrdlog/cpu.rrd:user:AVERAGE", + "DEF:system=$rrdlog/cpu.rrd:system:AVERAGE", + "DEF:idle=$rrdlog/cpu.rrd:idle:AVERAGE", + + "CDEF:total=user,system,idle,+,+", + "CDEF:userpct=100,user,total,/,*", + "CDEF:systempct=100,system,total,/,*", + "CDEF:idlepct=100,idle,total,/,*", + + "AREA:userpct#0000FF:User cpu usage\\j", + "STACK:systempct#FF0000:system cpu usage\\j", + "STACK:idlepct#00FF00:idle cpu usage\\j"); + + # "GPRINT:userpct:MAX:maximal user cpu\\:%3.2lf%%", + # "GPRINT:userpct:AVERAGE:average user cpu\\:%3.2lf%%", + # "GPRINT:userpct:LAST:current user cpu\\:%3.2lf%%\\j", + # "GPRINT:systempct:MAX:maximal system cpu\\:%3.2lf%%", + # "GPRINT:systempct:AVERAGE:average system cpu\\:%3.2lf%%", + # "GPRINT:systempct:LAST:current system cpu\\:%3.2lf%%\\j", + # "GPRINT:idlepct:MAX:maximal idle cpu\\:%3.2lf%%", + # "GPRINT:idlepct:AVERAGE:average idle cpu\\:%3.2lf%%", + # "GPRINT:idlepct:LAST:current idle cpu\\:%3.2lf%%\\j"); + $ERROR = RRDs::error; + print "Error in RRD::graph for cpu: $ERROR\n" if $ERROR; +} + +sub updatecpudata { + if ( ! -e "$rrdlog/cpu.rrd") { + RRDs::create ("$rrdlog/cpu.rrd", "--step=300", + "DS:user:COUNTER:600:0:U", + "DS:system:COUNTER:600:0:U", + "DS:idle:COUNTER:600:0:U", + + "RRA:AVERAGE:0.5:1:576", + "RRA:AVERAGE:0.5:6:672", + "RRA:AVERAGE:0.5:24:732", + "RRA:AVERAGE:0.5:144:1460"); + $ERROR = RRDs::error; + print "Error in RRD::create for cpu: $ERROR\n" if $ERROR; + } + + my ($cpu, $user, $nice, $system,$idle); + + open STAT, "/proc/stat"; + while(<STAT>) { + chomp; + /^cpu\s/ or next; + ($cpu, $user, $nice, $system, $idle) = split /\s+/; + last; + } + close STAT; + $user += $nice; + + RRDs::update ("$rrdlog/cpu.rrd", + "-t", "user:system:idle", + "N:$user:$system:$idle"); + $ERROR = RRDs::error; + print "Error in RRD::update for cpu: $ERROR\n" if $ERROR; + + print "N:$user:$system:$idle\n"; +} diff --git a/src/com.gluster.storage.management.gateway.scripts/src/rrd_mem.pl b/src/com.gluster.storage.management.gateway.scripts/src/rrd_mem.pl new file mode 100755 index 00000000..5c47cd81 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/rrd_mem.pl @@ -0,0 +1,100 @@ +#!/usr/bin/perl + +use RRDs; + +my $rrdlog = '/var/lib/rrd'; +my $graphs = '/var/lib/rrd'; + +updatememdata (); +#updatememgraph ('day'); +#updatememgraph ('week'); +#updatememgraph ('month'); +#updatememgraph ('year'); + +sub updatememgraph { + my $period = $_[0]; + + RRDs::graph ("$graphs/memory-$period.png", + "--start", "-1$period", "-aPNG", "-i", "-z", + "--alt-y-grid", "-w 300", "-h 50", "-l 0", "-u 100", "-r", + "--color", "SHADEA#FFFFFF", + "--color", "SHADEB#FFFFFF", + "--color", "BACK#FFFFFF", + "-t memory usage per $period", + "DEF:used=$rrdlog/mem.rrd:memused:AVERAGE", + "DEF:free=$rrdlog/mem.rrd:memfree:AVERAGE", + "DEF:cache=$rrdlog/mem.rrd:memcache:AVERAGE", + "CDEF:total=used,free,+", + "CDEF:used1=used,buffer,cache,-,-", + "CDEF:usedpct=100,used1,total,/,*", + "CDEF:free1=total,used1,-", + "CDEF:cachepct=100,cache,total,/,*", + "CDEF:freepct=100,free1,total,/,*", + "AREA:usedpct#0000FF:used memory\\j", + "STACK:cachepct#FFFF00:cached memory\\j", + "STACK:freepct#00FF00:free memory\\j"); + $ERROR = RRDs::error; + print "Error in RRD::graph for mem: $ERROR\n" if $ERROR; + + RRDs::graph ("$graphs/swap-$period.png", + "--start", "-1$period", "-aPNG", "-i", "-z", + "--alt-y-grid", "-w 300", "-h 50", "-l 0", "-u 100", "-r", + "--color", "SHADEA#FFFFFF", + "--color", "SHADEB#FFFFFF", + "--color", "BACK#FFFFFF", + "-t swap usage per $period", + "DEF:used=$rrdlog/mem.rrd:swapused:AVERAGE", + "DEF:free=$rrdlog/mem.rrd:swapfree:AVERAGE", + "CDEF:total=used,free,+", + "CDEF:usedpct=100,used,total,/,*", + "CDEF:freepct=100,free,total,/,*", + "AREA:usedpct#0000FF:used swap\\j", + "STACK:freepct#00FF00:free swap\\j"); + $ERROR = RRDs::error; + print "Error in RRD::graph for swap: $ERROR\n" if $ERROR; +} + +sub updatememdata { + my ($memused, $memfree, $memshared, $membuffers, $memcache, $swapused, $swapfree); + if ( ! -e "$rrdlog/mem.rrd") { + RRDs::create ("$rrdlog/mem.rrd", "--step=300", + "DS:memused:ABSOLUTE:600:0:U", + "DS:memfree:ABSOLUTE:600:0:U", + "DS:memcache:ABSOLUTE:600:0:U", + "DS:membuffer:ABSOLUTE:600:0:U", + "DS:swapused:ABSOLUTE:600:0:U", + "DS:swapfree:ABSOLUTE:600:0:U", + "RRA:AVERAGE:0.5:1:576", + "RRA:AVERAGE:0.5:6:672", + "RRA:AVERAGE:0.5:24:732", + "RRA:AVERAGE:0.5:144:1460"); + $ERROR = RRDs::error; + print "Error in RRD::create for mem: $ERROR\n" if $ERROR; + } + + my @memdata = `free -b -o`; + + my $temp = $memdata[1]; + + chomp( $temp ); + my @tempa = split (/\s+/, $temp); + $memused = $tempa [2]; + $memfree = $tempa [3]; + $memshared = $tempa [4]; + $membuffers = $tempa [5]; + $memcache = $tempa [6]; + + $temp = $memdata[2]; + chomp( $temp ); + @tempa = split (/\s+/, $temp); + $swapused = $tempa [2]; + $swapfree = $tempa [3]; + + + RRDs::update ("$rrdlog/mem.rrd", + "-t", "memused:memfree:memcache:membuffer:swapused:swapfree", + "N:$memused:$memfree:$memcache:$membuffers:$swapused:$swapfree"); + + $ERROR = RRDs::error; + print "Error in RRD::update for mem: $ERROR\n" if $ERROR; +} diff --git a/src/com.gluster.storage.management.gateway.scripts/src/rrd_net.pl b/src/com.gluster.storage.management.gateway.scripts/src/rrd_net.pl new file mode 100755 index 00000000..03f4f492 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/rrd_net.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +use RRDs; + +my $rrdlog = '/var/lib/rrd'; +my $graphs = '/var/lib/rrd'; + +updatenetdata(); +#updatenetgraph('hour'); +#updatenetgraph('day'); +#updatenetgraph('week'); +#updatenetgraph('month'); +#updatenetgraph('year'); + +sub updatenetgraph { + my $period = $_[0]; + + foreach $rrdfile (<$rrdlog/network-*.rrd>) { + RRDs::graph ("$graphs/network-$device-$period.png", + "--start", "-1$period", "-aPNG", "-i", "-z", + "--alt-y-grid", "-w 800", "-h 400", "-l 0", "-u 10000000", "-r", + "--color", "SHADEA#FFFFFF", + "--color", "SHADEB#FFFFFF", + "--color", "BACK#FFFFFF", + "-t $device load per $period", + "DEF:received=$rrdfile:received:AVERAGE", + "DEF:transmitted=$rrdfile:transmitted:AVERAGE", + + "LINE2:received#FF0000:received load\\j", + "LINE1:transmitted#0000FF:transmitted load\\j"); + + $ERROR = RRDs::error; + print "Error in RRD::graph for network $device: $ERROR\n" if $ERROR; + } +} + +sub updatenetdata { + open NETDEV, "/proc/net/dev"; + while (<NETDEV>) { + chomp; + s/^\s+//; # remove left side whitespaces + /:.+/ or next; # if input line contains ':' else continue + next if /^lo:\s/; # continue if input line starts with 'lo:' + + @tokens1 = split /:/; + @tokens2 = split(/\s+/, $tokens1[1]); + + $device = $tokens1[0]; + $received = $tokens2[0]; + $transmitted = $tokens2[8]; + + #print "$device, $received, $transmitted \n"; + + if ( ! -e "$rrdlog/network-$device.rrd") { + RRDs::create ("$rrdlog/network-$device.rrd", "--step=300", + "DS:received:COUNTER:600:0:U", + "DS:transmitted:COUNTER:600:0:U", + + "RRA:AVERAGE:0.5:1:576", + "RRA:AVERAGE:0.5:6:672", + "RRA:AVERAGE:0.5:24:732", + "RRA:AVERAGE:0.5:144:1460"); + $ERROR = RRDs::error; + print "Error in RRD::create for device $device: $ERROR\n" if $ERROR; + } + + RRDs::update ("$rrdlog/network-$device.rrd", + "-t", "received:transmitted", + "N:$received:$transmitted"); + $ERROR = RRDs::error; + print "Error in RRD::update for net: $ERROR\n" if $ERROR; + } + close NETDEV +} diff --git a/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_cpu_details.py b/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_cpu_details.py new file mode 100755 index 00000000..73982971 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_cpu_details.py @@ -0,0 +1,90 @@ +#!/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 sys +from XmlHandler import ResponseXml +import Utils + +def createMemData(file, step): + rs = ResponseXml() + command = ["rrdtool", "create", file, "--step=%s" % step, + "DS:user:COUNTER:600:0:U", + "DS:system:COUNTER:600:0:U", + "DS:idle:COUNTER:600:0:U", + "RRA:AVERAGE:0.5:1:576", + "RRA:AVERAGE:0.5:6:672", + "RRA:AVERAGE:0.5:24:732", + "RRA:AVERAGE:0.5:144:1460"] + + rv = Utils.runCommand(command, output=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to create RRD file for cpu usages %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return None + +def updateMemData(file): + rs = ResponseXml() + user = None + system = None + idle = None + for line in open("/proc/stat").readlines(): + if line.startswith("cpu"): + cpudetails = line.split() + if "cpu" == cpudetails[0]: + user = cpudetails[1] + system = cpudetails[3] + idle = cpudetails[4] + break + + if None == user: + Utils.log("failed to fetch cpu details from /proc/stat") + rs.appendTagRoute("status.code", "-1") + rs.appendTagRoute("status.message", "failed to fetch cpu details") + return rs.toxml() + + command = ["rrdtool", "update", file, "-t", "user:system:idle", + "N:%s:%s:%s" % (user, system, idle)] + rv = Utils.runCommand(command, output=True, root=True) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message = "Error: [%s]" % (error) + Utils.log("failed to update cpu usage into rrd file %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return None + + +def main(): + cpuRrdFile = "/var/lib/rrd/cpu.rrd" + if not os.path.exists(cpuRrdFile): + status = createMemData(cpuRrdFile, 100) + if status: + print status + status = updateMemData(cpuRrdFile) + if status: + print status + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_memory_details.py b/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_memory_details.py new file mode 100755 index 00000000..fe4fcce6 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/rrd_update_memory_details.py @@ -0,0 +1,90 @@ +#!/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 sys +from XmlHandler import ResponseXml +import Utils + +def createMemData(file, step): + rs = ResponseXml() + command = ["rrdtool", "create", file, "--step=%s" % step, + "DS:memused:ABSOLUTE:600:0:U", + "DS:memfree:ABSOLUTE:600:0:U", + "DS:memcache:ABSOLUTE:600:0:U", + "DS:swapused:ABSOLUTE:600:0:U", + "DS:swapfree:ABSOLUTE:600:0:U", + "RRA:AVERAGE:0.5:1:576", + "RRA:AVERAGE:0.5:6:672", + "RRA:AVERAGE:0.5:24:732", + "RRA:AVERAGE:0.5:144:1460"] + + rv = Utils.runCommand(command, output=True, root=True) + message = Utils.stripEmptyLines(rv["Stdout"]) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to create RRD file for memory usages %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return None + +def updateMemData(file): + rs = ResponseXml() + command = ["free", "-b", "-o"] + rv = Utils.runCommand(command, output=True, root=True) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log("failed to retrieve memory details") + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + + message = rv["Stdout"].split() + command = ["rrdtool", "update", file, "-t", "memused:memfree:memcache:swapused:swapfree", + "N:%s:%s:%s:%s:%s" % (message[8], message[9], message[12], message[14], message[15])] + rv = Utils.runCommand(command, output=True, root=True) + if rv["Stderr"]: + error = Utils.stripEmptyLines(rv["Stderr"]) + message += "Error: [%s]" % (error) + Utils.log(syslog.LOG_ERR, "failed to update memory usage into rrd file %s" % file) + rs.appendTagRoute("status.code", rv["Status"]) + rs.appendTagRoute("status.message", message) + return rs.toxml() + return None + + +def main(): + #if len(sys.argv) != 2: + # print >> sys.stderr, "usage: %s <step>" % sys.argv[0] + # sys.exit(-1) + #step = sys.argv[1] + + memRrdFile = "mem.rrd" + if not os.path.exists(memRrdFile): + status = createMemData(memRrdFile, 100) + if status: + print status + status = updateMemData(memRrdFile) + if status: + print status + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/setup_cifs_config.py b/src/com.gluster.storage.management.gateway.scripts/src/setup_cifs_config.py new file mode 100755 index 00000000..2cc35acc --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/setup_cifs_config.py @@ -0,0 +1,81 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils + +def main(): + try: + os.mkdir(Globals.GLUSTER_BASE_DIR) + os.mkdir(Globals.VOLUME_CONF_DIR) + os.mkdir(Globals.CIFS_EXPORT_DIR) + os.mkdir(Globals.REEXPORT_DIR) + except OSError, e: + Utils.log("failed to create directory: %s" % str(e)) + sys.exit(1) + try: + fp = open(Globals.VOLUME_SMBCONF_FILE, "w") + fp.close() + except IOError, e: + Utils.log("Failed to create file %s: %s" % (Globals.VOLUME_SMBCONF_FILE, str(e))) + sys.exit(2) + try: + os.rename(Globals.SAMBA_CONF_FILE, "%s.orig" % Globals.SAMBA_CONF_FILE) + except IOError, e: + Utils.log("Ignoring rename %s to %s: %s" % (Globals.SAMBA_CONF_FILE, "%s.orig" % Globals.SAMBA_CONF_FILE, str(e))) + try: + fp = open(Globals.SAMBA_CONF_FILE, "w") + fp.write("##\n") + fp.write("## THIS FILE SHOULD NOT BE MODIFIED. IF YOU WANT TO MODIFY SAMBA\n") + fp.write("## CONFIGURATIONS, USE /etc/samba/real.smb.conf FILE\n") + fp.write("##\n") + fp.write("include = %s\n\n" % Globals.REAL_SAMBA_CONF_FILE) + fp.write("## CAUTION: DO NOT REMOVE BELOW LINE. REMOVAL OF THE LINE DISABLES\n") + fp.write("## CIFS REEXPORT OF GLUSTER VOLUMES\n") + fp.write("include = %s\n" % Globals.VOLUME_SMBCONF_FILE) + fp.close() + except IOError, e: + Utils.log("Failed to create samba configuration file %s: %s" % (Globals.SAMBA_CONF_FILE, str(e))) + sys.exit(3) + try: + fp = open(Globals.REAL_SAMBA_CONF_FILE, "w") + fp.write("[global]\n") + fp.write("## CAUTION: DO NOT REMOVE BELOW INCLUDE LINE. REMOVAL OF THE LINE\n") + fp.write("## DISABLES SERVER/CIFS HIGH AVAILABILITY\n") + #fp.write("include = %s\n" % Globals.CTDB_SAMBA_CONF_FILE) + fp.write("##\n") + fp.write("socket options = TCP_NODELAY IPTOS_LOWDELAY SO_SNDBUF=131072 SO_RCVBUF=131072\n") + fp.write("read raw = yes\n") + fp.write("server string = %h\n") + fp.write("write raw = yes\n") + fp.write("oplocks = yes\n") + fp.write("max xmit = 131072\n") + fp.write("dead time = 15\n") + fp.write("getwd cache = yes\n") + fp.write("#read size = 131072\n") + fp.write("use sendfile=yes\n") + fp.write("block size = 131072\n") + fp.write("printcap name = /etc/printcap\n") + fp.write("load printers = no\n") + fp.close() + except IOError, e: + Utils.log("Failed to create samba configuration file %s: %s" % (Globals.REAL_SAMBA_CONF_FILE, str(e))) + sys.exit(4) + + + if Utils.runCommand("setsebool -P samba_share_fusefs on") != 0: + Utils.log("failed to set SELinux samba_share_fusefs") + sys.exit(5) + + if Utils.runCommand("service smb restart") != 0: + Utils.log("failed to restart smb service") + sys.exit(6) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/start_volume_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/start_volume_cifs.py new file mode 100755 index 00000000..239216c3 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/start_volume_cifs.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils +import VolumeUtils + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s VOLUME_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + + volumeMountDirName = "%s/%s" % (Globals.REEXPORT_DIR, volumeName) + cifsDirName = "%s/%s" % (Globals.CIFS_EXPORT_DIR, volumeName) + + if Utils.runCommand("mount -t glusterfs 127.0.0.1:%s %s" % (volumeName, volumeMountDirName)) != 0: + Utils.log("Failed to mount volume %s" % (volumeName)) + sys.exit(1) + if Utils.runCommand("ln -fTs %s %s" % (volumeMountDirName, cifsDirName)) != 0: + Utils.log("Failed to create reexport link %s" % cifsDirName) + sys.exit(2) + if Utils.runCommand("chcon -t samba_share_t %s -h" % cifsDirName) != 0: + Utils.log("Failed to change security context for the link %s" % cifsDirName) + sys.exit(2) + if not VolumeUtils.includeVolume(volumeName): + Utils.log("Failed to include volume for CIFS reexport") + sys.exit(3) + if Utils.runCommand("service smb reload") != 0: + Utils.log("Failed to reload smb service") + sys.exit(4) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/src/com.gluster.storage.management.gateway.scripts/src/stop_volume_cifs.py b/src/com.gluster.storage.management.gateway.scripts/src/stop_volume_cifs.py new file mode 100755 index 00000000..99ac4750 --- /dev/null +++ b/src/com.gluster.storage.management.gateway.scripts/src/stop_volume_cifs.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com> +# This file is part of Gluster Management Gateway. +# + +import os +import sys +import Globals +import Utils +import VolumeUtils + +def main(): + if len(sys.argv) != 2: + sys.stderr.write("usage: %s VOLUME_NAME\n" % os.path.basename(sys.argv[0])) + sys.exit(-1) + + volumeName = sys.argv[1] + + volumeMountDirName = "%s/%s" % (Globals.REEXPORT_DIR, volumeName) + cifsDirName = "%s/%s" % (Globals.CIFS_EXPORT_DIR, volumeName) + + if not Utils.removeFile(cifsDirName): + Utils.log("Failed to remove reexport link %s" % cifsDirName) + sys.exit(1) + if not VolumeUtils.excludeVolume(volumeName): + Utils.log("Failed to exclude volume for CIFS reexport") + sys.exit(2) + if Utils.runCommand("service smb reload") != 0: + Utils.log("Failed to reload smb service") + sys.exit(3) + if Utils.runCommand("umount %s" % (volumeMountDirName)) != 0: + Utils.log("Failed to unmount volume %s" % (volumeName)) + sys.exit(4) + sys.exit(0) + + +if __name__ == "__main__": + main() |
