summaryrefslogtreecommitdiffstats
path: root/src/com.gluster.storage.management.server.scripts
diff options
context:
space:
mode:
authorShireesh Anjal <anjalshireesh@gmail.com>2011-03-28 06:58:51 -0700
committerShireesh Anjal <anjalshireesh@gmail.com>2011-03-28 06:58:51 -0700
commitbf531d097bc99db08bda4d1a1dec541c57c7933c (patch)
tree253a3fc82d5bac3755fc7e32f8456879b69b9979 /src/com.gluster.storage.management.server.scripts
parentb27c5d68d3ffa47c92e0fcd7d0873ac2d6b8fca8 (diff)
Preparing src for migration to github
Diffstat (limited to 'src/com.gluster.storage.management.server.scripts')
-rw-r--r--src/com.gluster.storage.management.server.scripts/.project17
-rw-r--r--src/com.gluster.storage.management.server.scripts/.pydevproject10
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/Commands.py78
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/Common.py34
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/Globals.py119
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/NetworkUtils.py422
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/Protocol.py438
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/Utils.py704
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/common/system-config-network-tui-1.3.99.18-1.el5.noarch.rpmbin0 -> 1915520 bytes
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/Agent.py118
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py96
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py179
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py76
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py308
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/Socket.py47
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py346
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py45
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/server/RemoteExecute.py287
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/server/RequestHandler.py58
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/server/TransportAgent.py26
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/server/transport.py94
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/server/vmware-discover-servers.py83
22 files changed, 3585 insertions, 0 deletions
diff --git a/src/com.gluster.storage.management.server.scripts/.project b/src/com.gluster.storage.management.server.scripts/.project
new file mode 100644
index 00000000..beda33b7
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.gluster.storage.management.server.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.server.scripts/.pydevproject b/src/com.gluster.storage.management.server.scripts/.pydevproject
new file mode 100644
index 00000000..0a912df5
--- /dev/null
+++ b/src/com.gluster.storage.management.server.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.server.scripts/src</path>
+</pydev_pathproperty>
+</pydev_project>
diff --git a/src/com.gluster.storage.management.server.scripts/src/common/Commands.py b/src/com.gluster.storage.management.server.scripts/src/common/Commands.py
new file mode 100644
index 00000000..c728b565
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/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.server.scripts/src/common/Common.py b/src/com.gluster.storage.management.server.scripts/src/common/Common.py
new file mode 100644
index 00000000..60f200fe
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/Common.py
@@ -0,0 +1,34 @@
+# 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
+
+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
diff --git a/src/com.gluster.storage.management.server.scripts/src/common/Globals.py b/src/com.gluster.storage.management.server.scripts/src/common/Globals.py
new file mode 100644
index 00000000..365d4af7
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/Globals.py
@@ -0,0 +1,119 @@
+# 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 = "transport"
+INSTALLER_SERVER_NAME = "$installer$"
+
+GLUSTER_BASE_DIR = "/GLUSTER"
+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/platform"
+
+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"
+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 = {}
+##
diff --git a/src/com.gluster.storage.management.server.scripts/src/common/NetworkUtils.py b/src/com.gluster.storage.management.server.scripts/src/common/NetworkUtils.py
new file mode 100644
index 00000000..1ce1b132
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/NetworkUtils.py
@@ -0,0 +1,422 @@
+# 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 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 device in getHardwareList():
+ netDevice = {}
+ netDevice["device"] = None
+ netDevice["description"] = None
+ netDevice["hwaddr"] = None
+ netDevice["type"] = None
+ netDevice["onboot"] = None
+ netDevice["bootproto"] = None
+ netDevice["ipaddr"] = None
+ netDevice["netmask"] = 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["description"] = device.Description
+ netDevice["type"] = device.Type
+ netDevice["link"] = getLinkStatus(device.Name)
+ netDevice["mode"] = getBondMode(device.Name, root + Globals.MODPROBE_CONF_FILE)
+ try:
+ netDevice["hwaddr"] = open("/sys/class/net/%s/address" % device.Name).read().strip()
+ except IOError:
+ pass
+ netDeviceList.append(netDevice)
+
+ conf = readIfcfgConfFile(device.Name, root)
+ if not conf:
+ continue
+ try:
+ netDevice["onboot"] = conf["onboot"]
+ except KeyError:
+ pass
+ try:
+ netDevice["bootproto"] = conf["bootproto"]
+ except KeyError:
+ pass
+ try:
+ netDevice["ipaddr"] = conf["ipaddr"]
+ except KeyError:
+ pass
+ try:
+ netDevice["netmask"] = conf["netmask"]
+ except KeyError:
+ pass
+ try:
+ netDevice["gateway"] = conf["gateway"]
+ except KeyError:
+ pass
+ 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.server.scripts/src/common/Protocol.py b/src/com.gluster.storage.management.server.scripts/src/common/Protocol.py
new file mode 100644
index 00000000..ff073593
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/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.server.scripts/src/common/Utils.py b/src/com.gluster.storage.management.server.scripts/src/common/Utils.py
new file mode 100644
index 00000000..c605eecd
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/Utils.py
@@ -0,0 +1,704 @@
+# 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 log(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():
+ return tempfile.mkstemp(prefix="GSP_")[1]
+
+
+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)
+ 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 getLoadavg():
+ """-> 5-tuple containing the following numbers in order:
+ - 1-minute load average (float)
+ - 5-minute load average (float)
+ - 15-minute load average (float)
+ - Number of threads/processes currently executing (<= number of
+ CPUs) (int)
+ - Number of threads/processes that exist on the system (int)
+ - The PID of the most recently-created process on the system (int)
+ """
+ loadavgstr = open('/proc/loadavg', 'r').readline().strip()
+ data = loadavgstr.split()
+ avg1, avg5, avg15 = map(float, data[:3])
+ threads_and_procs_running, threads_and_procs_total = map(int,
+ data[3].split('/'))
+ most_recent_pid = int(data[4])
+ ncpus = 1
+ final_avg = ""
+ if hasattr(os, "sysconf"):
+ if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ # Linux
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(ncpus, int) and ncpus > 0:
+ final_avg = "%.2f" % (1.0 * avg1 / ncpus)
+
+ # Future return everything when needed
+ # Commenting this for the time being
+ # avg5, avg15, threads_and_procs_running, threads_and_procs_total, most_recent_pid
+ return final_avg
+
+
+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:
+ Utils.log("Failed to remove file %s: %s" % (fileName, e))
+ return False
+
+
+def isLiveMode():
+ return os.path.exists(Globals.LIVE_MODE_FILE)
diff --git a/src/com.gluster.storage.management.server.scripts/src/common/system-config-network-tui-1.3.99.18-1.el5.noarch.rpm b/src/com.gluster.storage.management.server.scripts/src/common/system-config-network-tui-1.3.99.18-1.el5.noarch.rpm
new file mode 100644
index 00000000..4b07c4e4
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/common/system-config-network-tui-1.3.99.18-1.el5.noarch.rpm
Binary files differ
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/Agent.py b/src/com.gluster.storage.management.server.scripts/src/nodes/Agent.py
new file mode 100644
index 00000000..6d867d9e
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/Agent.py
@@ -0,0 +1,118 @@
+# 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 xmpp
+import sys
+import syslog
+
+class Agent:
+ def __init__(self, jidString, jidResource, password, proxySettings=None):
+ if jidString and jidResource and password:
+ self.password = password
+ self.proxySettings = proxySettings
+ self.jid = xmpp.protocol.JID(jid=jidString)
+ self.jid.setResource(jidResource)
+ self.xmppClient = xmpp.Client(self.jid.getDomain(), debug=[])
+ self.presenceHandler = None
+ self.messageHandler = None
+ return
+ raise ValueError("jid, resource and password should not be empty")
+
+ def registerPresenceHandler(self, function):
+ self.presenceHandler = function
+
+ def registerMessageHandler(self, function):
+ self.messageHandler = function
+
+ def __defaultMessageHandler(self, connection, event):
+ syslog.syslog(syslog.LOG_DEBUG,
+ "[Received]: from_jid=%s, type=%s, message=%s, error=%s\n" %
+ (event.getFrom(), event.getType(), event.getBody(), event.getError()))
+ if self.messageHandler:
+ self.messageHandler(connection, event)
+ else:
+ sys.stderr.write("[Message]: from_jid=%s, type=%s, message=%s, error=%s\n" %
+ (event.getFrom(), event.getType(), event.getBody(), event.getError()))
+
+ def __defaultPresenceHandler(self, connection, event):
+ syslog.syslog(syslog.LOG_DEBUG,
+ "[Presence]: from_jid=%s, type=%s, status=%s, error=%s\n" %
+ (event.getFrom(), event.getType(), event.getShow(), event.getError()))
+ if self.presenceHandler:
+ self.presenceHandler(connection, event)
+ else:
+ sys.stderr.write("[Presence]: from_jid=%s, type=%s, status=%s, error=%s\n" %
+ (event.getFrom(), event.getType(), event.getShow(), event.getError()))
+
+ def connect(self):
+ syslog.syslog("Connecting to server %s\n" % self.jid.getDomain())
+ connection = self.xmppClient.connect()
+ if not connection:
+ syslog.syslog("failed\n")
+ if not self.proxySettings:
+ return False
+ syslog.syslog("Connecting to server %s through proxy server %s, port %s, username %s\n" %
+ (self.jid.getDomain(),
+ self.proxySettings["host"],
+ self.proxySettings["port"],
+ self.proxySettings["user"]))
+ connection = self.xmppClient.connect(proxy=self.proxySettings)
+ if not connection:
+ syslog.syslog("failed\n")
+ return False
+
+ syslog.syslog("Authenticating with username %s\n" % self.jid)
+ auth = self.xmppClient.auth(self.jid.getNode(),
+ self.password,
+ self.jid.getResource())
+ if not auth:
+ syslog.syslog("failed\n")
+ return False
+ syslog.syslog("done\n")
+ syslog.syslog("connection type is %s. authentication type is %s\n" % (connection, auth))
+
+ self.xmppClient.RegisterHandler("presence", self.__defaultPresenceHandler)
+ self.xmppClient.RegisterHandler("message", self.__defaultMessageHandler)
+
+ self.xmppClient.sendInitPresence()
+ return True
+
+ def disconnect(self):
+ self.xmppClient.disconnect()
+
+ def processMessage(self, timeout=1):
+ return self.xmppClient.Process(timeout)
+ #if not self.xmppClient.isConnected():
+ # self.xmppClient.reconnectAndReauth()
+
+ def sendMessage(self, jidString, message, messageType="chat"):
+ syslog.syslog(syslog.LOG_DEBUG,
+ "[send]: from_jid=%s, type=%s, message=%s\n" %
+ (jidString, messageType, message))
+ self.xmppClient.send(xmpp.protocol.Message(to=jidString,
+ body=message,
+ typ=messageType))
+
+ def getNetworkSocket(self):
+ return self.xmppClient.Connection._sock;
+
+ def getRoster(self):
+ return self.xmppClient.getRoster()
+
+ def isConnected(self):
+ return self.xmppClient.isConnected()
+##--end of Agent
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py b/src/com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py
new file mode 100644
index 00000000..3311eb56
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/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.server.scripts/src/nodes/ServerAgent.py b/src/com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py
new file mode 100755
index 00000000..bcb2bac1
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py
@@ -0,0 +1,179 @@
+#!/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 signal
+import atexit
+import socket
+import syslog
+import pwd
+from optparse import OptionParser
+
+import Globals
+import Socket
+import Utils
+import ServerRequestHandler
+
+
+ME = os.path.basename(sys.argv[0])
+PID_FILE = "/var/run/serveragent.pid"
+serverSocket = None
+clientSocket = None
+clientAddress = None
+clientInputStream = None
+clientOutputStream = None
+
+
+def sigTermHandler(signal, frame):
+ sys.exit(0)
+
+
+def cleanup():
+ try:
+ if os.path.exists(PID_FILE):
+ os.unlink(PID_FILE)
+ except OSError, e:
+ Utils.log("Failed to remove PID file %s: %s" % (PID_FILE, str(e)))
+
+ try:
+ if clientSocket:
+ clientSocket.close()
+ except socket.error, e:
+ Utils.log("Failed to close client socket: %s" % str(e))
+
+ try:
+ if serverSocket:
+ serverSocket.close()
+ except socket.error, e:
+ Utils.log("Failed to close server socket: " % str(e))
+
+
+def main():
+ global PID_FILE
+ global serverSocket
+ global clientSocket
+ global clientAddress
+ global clientInputStream
+ global clientOutputStream
+
+ username = Globals.SERVER_AGENT_RUN_USERNAME
+
+ Utils.openLog(Globals.SERVER_AGENT_LOG_FILE)
+
+ parser = OptionParser(version="%s %s" % (ME, Globals.GLUSTER_PLATFORM_VERSION))
+
+ parser.add_option("-N", "--no-daemon",
+ action="store_false", dest="daemonMode", default=True,
+ help="Run in foreground")
+ parser.add_option("-r", "--run-as", dest="username",
+ help="Run the daemon as USERNAME (default: %s)" % Globals.SERVER_AGENT_RUN_USERNAME,
+ metavar="USERNAME")
+ (options, args) = parser.parse_args()
+
+ if options.username:
+ username = options.username
+ try:
+ userInfo = pwd.getpwnam(username)
+ except KeyError, e:
+ sys.stderr.write("%s\n" % str(e))
+ serverSocket.close()
+ sys.exit(-1)
+ uid = userInfo.pw_uid
+ gid = userInfo.pw_gid
+
+ try:
+ Utils.log("__DEBUG__ Opening server socket on port %s" % Globals.SERVER_AGENT_PORT)
+ serverSocket = Socket.openServerSocket()
+ except socket.error, e:
+ sys.stderr.write("Failed to open server socket: %s\n" % str(e))
+ sys.exit(-1)
+
+ if options.daemonMode:
+ if os.path.exists(PID_FILE):
+ sys.stderr.write("fatal: %s file exists\n" % PID_FILE)
+ serverSocket.close()
+ sys.exit(-1)
+
+ if not Utils.daemonize():
+ sys.stderr.write("fatal: unable to run as daemon\n")
+ serverSocket.close()
+ sys.exit(-1)
+ try:
+ fp = open(PID_FILE, "w")
+ fp.write("%s\n" % os.getpid())
+ fp.close()
+ except IOError, e:
+ Utils.log("Pid file %s: %s" % (PID_FILE, str(e)))
+ serverSocket.close()
+ sys.exit(-1)
+ try:
+ os.chown(PID_FILE, uid, gid)
+ except OSError, e:
+ Utils.log("Pid file %s: %s" % (PID_FILE, str(e)))
+ serverSocket.close()
+ try:
+ os.unlink(PID_FILE)
+ except OSError, ex:
+ Utils.log("Failed to remove PID file %s: %s" % (PID_FILE, str(ex)))
+ sys.exit(-1)
+ else:
+ Globals.GLUSTER_DEBUG = True
+
+ try:
+ os.setregid(gid, gid)
+ except OSError, e:
+ Utils.log("Failed to set effective and real gid to %s: %s" % (gid, str(e)))
+ cleanup()
+ sys.exit(-1)
+ try:
+ os.setreuid(uid, uid)
+ except OSError, e:
+ Utils.log("Failed to set effective and real uid to %s: %s" % (uid, str(e)))
+ cleanup()
+ sys.exit(-1)
+
+ atexit.register(cleanup)
+ signal.signal(signal.SIGTERM, sigTermHandler)
+
+ while True:
+ Utils.log("__DEBUG__ Waiting for new connection on port %s" % Globals.SERVER_AGENT_PORT)
+ try:
+ clientSocket, clientAddress, clientInputStream, clientOutputStream = Socket.acceptClient(serverSocket)
+ except socket.error, e:
+ Utils.log("Failed to accept new connection: %s" % str(e))
+ sys.exit(-1)
+
+ Utils.log('__DEBUG__ Connected by %s' % str(clientAddress))
+ try:
+ requestString = Socket.readPacket(clientInputStream)
+ Utils.log('__DEBUG__ Received %s' % repr(requestString))
+ responseString = ServerRequestHandler.handleRequest(requestString)
+ if responseString:
+ Socket.writePacket(clientOutputStream, responseString)
+ clientOutputStream.flush()
+ else:
+ Utils.log('__DEBUG__ empty response string')
+ Utils.log('__DEBUG__ Closing client %s' % str(clientAddress))
+ clientSocket.close()
+ except socket.error, e:
+ Utils.log("Socket error on client: %s" % str(e))
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py b/src/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py
new file mode 100644
index 00000000..31d4eb8c
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py
@@ -0,0 +1,76 @@
+# 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 Commands
+from Protocol import *
+from Globals import *
+from GetServerNetworkConfig import *
+
+def handleRequestGetServerNetworkConfig(requestDom):
+ return getServerNetworkConfig(requestDom)
+
+def handleRequest(requestString):
+ log("Received request %s" % repr(requestString))
+
+ requestDom = XDOM()
+ requestDom.parseString(requestString)
+ if not requestDom:
+ log("Invalid request")
+ return None
+
+ preRequestMap = {}
+
+ postRequestMap = {}
+
+ cleanupRequestMap = {}
+
+ requestMap = { Commands.COMMAND_GET_SERVER_NETWORK_CONFIG : handleRequestGetServerNetworkConfig }
+
+ messageId = requestDom.getMessageId()
+ if not messageId:
+ log("Invalid message Id")
+ return None
+
+ requestCommand = requestDom.getRequestCommand()
+ if not requestCommand:
+ log("invalid request command")
+ return None
+
+ requestAction = requestDom.getRequestAction()
+ version = requestDom.getVersion()
+ #if not isSupportedVersion(version):
+ # log("Unsupported version request %s" % requestDom.toxml())
+ # return ResponseXml(requestCommand, "Unsupported version request", messageId, version).toxml()
+
+ try:
+ if not requestAction:
+ responseDom = requestMap[requestCommand](requestDom)
+ elif requestAction.upper() == "PRE":
+ responseDom = preRequestMap[requestCommand](requestDom)
+ elif requestAction.upper() == "POST":
+ responseDom = postRequestMap[requestCommand](requestDom)
+ elif requestAction.upper() == "CLEANUP":
+ responseDom = cleanupRequestMap[requestCommand](requestDom)
+ else:
+ log("Unknown request action %s" % requestAction)
+ return None
+ return responseDom.toxml()
+ except KeyError:
+ log("No handler found for command %s for action %s" % (requestCommand, requestAction))
+ return ResponseXml(requestCommand, "Invalid command", messageId, version).toxml()
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py b/src/com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py
new file mode 100644
index 00000000..1fec994c
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/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.server.scripts/src/nodes/Socket.py b/src/com.gluster.storage.management.server.scripts/src/nodes/Socket.py
new file mode 100644
index 00000000..ba6b6ad0
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/Socket.py
@@ -0,0 +1,47 @@
+import socket
+import sys
+import Globals
+
+def openServerSocket(bindAddress="", port=Globals.SERVER_AGENT_PORT):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind((bindAddress, port))
+ sock.listen(1)
+ return sock
+
+
+def connectToServer(serverName, port=Globals.SERVER_AGENT_PORT):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((serverName, port))
+ print "__DEBUG__ connected to ", serverName, " on port ", port
+ inputStream = sock.makefile("r")
+ outputStream = sock.makefile("w")
+ return sock, inputStream, outputStream
+
+
+def acceptClient(serverSocket):
+ clientSocket, clientAddress = serverSocket.accept()
+ clientInputStream = clientSocket.makefile("r")
+ clientOutputStream = clientSocket.makefile("w")
+ return clientSocket, clientAddress, clientInputStream, clientOutputStream
+
+
+def readPacket(inputStream):
+ packetString = ""
+ while True:
+ line = inputStream.readline()
+ print "__DEBUG__", line
+ if not line:
+ break
+ if line.strip() == "":
+ # end of input received
+ return packetString
+ packetString += line
+ return packetString
+
+
+def writePacket(outputStream, packetString):
+ rv = outputStream.write(packetString.strip() + "\n\n")
+ outputStream.flush()
+
+
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py b/src/com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py
new file mode 100644
index 00000000..d5a1fe19
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/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.server.scripts/src/nodes/multicast_response.py b/src/com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py
new file mode 100644
index 00000000..64bc0899
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py
@@ -0,0 +1,45 @@
+#!/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 socket
+import struct
+import Globals
+
+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 request and request[0].upper() == "SERVERDISCOVERY":
+ socketSend.sendto(socket.gethostname(), (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.server.scripts/src/server/RemoteExecute.py b/src/com.gluster.storage.management.server.scripts/src/server/RemoteExecute.py
new file mode 100644
index 00000000..1800234f
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/server/RemoteExecute.py
@@ -0,0 +1,287 @@
+# 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 socket
+#import paramiko
+import syslog
+import sys
+import Socket
+import Globals
+from copy import deepcopy
+from ServerUtils import *
+
+SERVER_AGENT_COMMAND = "/usr/sbin/server-agent"
+SERVER_AGENT_CLEANUP_COMMAND = SERVER_AGENT_COMMAND + " --cleanup"
+SERVER_AGENT_PRE_COMMAND = SERVER_AGENT_COMMAND + " --pre"
+SERVER_AGENT_POST_COMMAND = SERVER_AGENT_COMMAND + " --post"
+TRANSPORT_USER_NAME = "transport"
+TRANSPORT_PRIVATE_KEY_FILE = Globals.TRANSPORT_HOME_DIR + "/.ssh/id_rsa"
+
+def remoteExecute(serverList, command, commandInput=None):
+ print "REMOTE:", serverList
+ statusDict = {}
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ try:
+ privateKey = paramiko.RSAKey.from_private_key_file(TRANSPORT_PRIVATE_KEY_FILE)
+ except IOError:
+ log(syslog.LOG_ERR, "Private key file %s not found" % TRANSPORT_PRIVATE_KEY_FILE)
+ return None
+ print "STAGE1"
+ for serverName in serverList.keys():
+ serverStatus = {}
+ serverStatus["ConnectionStatus"] = None
+ serverStatus["ExecutionStatus"] = None
+ serverStatus["StdOutString"] = None
+ serverStatus["StdErrString"] = None
+ serverStatus["ConnectedIp"] = None
+ serverStatus["Error"] = None
+
+ isConnected = False
+ for serverIp in serverList[serverName]:
+ try:
+ ssh.connect(serverIp, username=TRANSPORT_USER_NAME, pkey=privateKey)
+ isConnected = True
+ break
+ except socket.error:
+ log(syslog.LOG_ERR, "Server %s:%s is inaccessible" % (serverName, serverIp))
+ continue
+ if not isConnected:
+ serverStatus["ConnectionStatus"] = "inaccessible"
+ statusDict[serverName] = serverStatus
+ continue
+
+ try:
+ transport = ssh.get_transport()
+ channel = transport.open_session()
+ serverStatus["ConnectionStatus"] = True
+ channel.exec_command(command)
+ stdin = channel.makefile('wb')
+ stdout = channel.makefile('rb')
+ stderr = channel.makefile_stderr('rb')
+ if commandInput:
+ stdin.write(commandInput)
+ channel.shutdown_write()
+
+ returnValue = channel.recv_exit_status() ## this is blocking call
+ serverStatus["ExecutionStatus"] = returnValue
+ print "RRRRRRRRRRRRRRRR:", returnValue
+ errorString = ""
+ if -1 == returnValue:
+ errorString = stderr.read()
+ serverStatus["StdErrString"] = errorString
+ if "bash: " + command.split()[0] + ": command not found\n" == errorString:
+ log(syslog.LOG_ERR, "command %s not found in server %s" % (command, serverName))
+ serverStatus["Error"] = "Command not found"
+ else:
+ serverStatus["StdErrString"] = stderr.read()
+ serverStatus["StdOutString"] = stdout.read()
+ ssh.close()
+ except paramiko.SSHException:
+ # Channel error (channel not open)
+ log(syslog.LOG_ERR, "Server %s:%s connection aborted" % (serverName, serverIp))
+ serverStatus["ConnectionStatus"] = "aborted"
+ except socket.error:
+ log(syslog.LOG_ERR, "Server %s:%s is inaccessible" % (serverName, serverIp))
+ serverStatus["ConnectionStatus"] = "inaccessible"
+ except paramiko.AuthenticationException:
+ log(syslog.LOG_ERR, "Authentication error on server %s:%s of user %s" %
+ (serverName, serverIp, TRANSPORT_USER_NAME))
+ serverStatus["ConnectionStatus"] = "authentication error"
+ serverStatus["ConnectedIp"] = serverIp
+ statusDict[serverName] = serverStatus
+ return statusDict
+
+def cleanupExecuteSsh(serverList, requestDom):
+ return remoteExecute(serverList, SERVER_AGENT_CLEANUP_COMMAND, requestDom.toxml())
+
+def executeRequestCommandSsh(serverList, command, requestDom, cleanupFlag):
+ cleanupStatusDict = {}
+ successStatusDict = {}
+ failureServerList = {}
+ cleanupServerList = {}
+ serverList = deepcopy(serverList)
+ statusDict = remoteExecute(serverList, command, requestDom.toxml())
+ for serverName in statusDict.keys():
+ statusDict["Response"] = None
+ if statusDict[serverName]["ConnectionStatus"] == True:
+ setLastAccessedNetwork(serverName, statusDict[serverName]["ConnectedIp"])
+ if statusDict[serverName]["ConnectedIp"]:
+ ipList = serverList[serverName]
+ ipList.remove(statusDict[serverName]["ConnectedIp"])
+ cleanupServerList[serverName] = [statusDict[serverName]["ConnectedIp"]] + ipList
+ if statusDict[serverName]["ExecutionStatus"] != 0:
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ responseDom = XDOM()
+ if not responseDom.parseString(statusDict[serverName]["StdOutString"]):
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ statusDict["Response"] = responseDom
+ if "OK" != responseDom.getAttribute("response-code"):
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ successStatusDict[serverName] = statusDict[serverName]
+ if cleanupFlag and failureServerList:
+ cleanupStatusDict = remoteExecute(cleanupServerList, SERVER_AGENT_CLEANUP_COMMAND, requestDom.toxml())
+ return successStatusDict, failureServerList, cleanupStatusDict
+
+def preExecuteSsh(serverList, requestDom, cleanupFlag=True):
+ return executeRequestCommandSsh(serverList, SERVER_AGENT_PRE_COMMAND, requestDom, cleanupFlag)
+
+def executeSsh(serverList, requestDom, cleanupFlag=True):
+ return executeRequestCommandSsh(serverList, SERVER_AGENT_COMMAND, requestDom, cleanupFlag)
+
+def postExecuteSsh(serverList, requestDom, cleanupFlag=True):
+ return executeRequestCommandSsh(serverList, SERVER_AGENT_POST_COMMAND, requestDom, cleanupFlag)
+
+def runPullUpdatesDir(sourceServerIp, destServerIpList):
+ command = "/usr/sbin/pull-dir.sh %s %s %s" % (sourceServerIp,
+ Globals.UPDATES_DIR[1:],
+ Globals.UPDATES_DIR)
+ statusDict = remoteExecute(destServerIpList, command)
+ status = True
+ for serverName in statusDict.keys():
+ if statusDict[serverName]["ExecutionStatus"] != 0:
+ log(syslog.LOG_ERR, "Failed to execute [%s] in server %s" % (command, serverName))
+ status = False
+ return status
+
+def runPullGlusterDir(sourceServerIp, destServerIpList):
+ command = "/usr/sbin/pull-dir.sh %s %s %s" % (sourceServerIp,
+ Globals.GLUSTER_BASE_DIR[1:],
+ Globals.GLUSTER_BASE_DIR)
+ statusDict = remoteExecute(destServerIpList, command)
+ status = True
+ for serverName in statusDict.keys():
+ if statusDict[serverName]["ExecutionStatus"] != 0:
+ log(syslog.LOG_ERR, "Failed to execute [%s] in server %s" % (command, serverName))
+ status = False
+ return status
+
+def syncConfiguration(syncToInstaller=False, sourceServerIpList=None):
+ thisServerName = getCurrentServerName()
+ serverList = getAllServerList()
+ serverList.remove(thisServerName)
+ serverIpList = getExecuteServerList(serverList)
+ if syncToInstaller:
+ installerIp = getInstallerIp()
+ if not installerIp:
+ log(syslog.LOG_ERR, "Installer IP address is not found")
+ return False
+ serverIpList[Globals.INSTALLER_SERVER_NAME] = [installerIp]
+
+ if not serverIpList:
+ log(syslog.LOG_ERR, "No servers found for sync configuration")
+ return False
+
+ signature = generateSignature()
+ if not storeSignature(signature, Globals.SIGNATURE_FILE):
+ log(syslog.LOG_ERR, "failed to store signature %s to %s file" %
+ (signature, Globals.SIGNATURE_FILE))
+ return False
+
+ thisServerIpList = getExecuteServerList([thisServerName])
+ if sourceServerIpList:
+ thisServerIpList = sourceServerIpList
+ return runPullGlusterDir(thisServerIpList[thisServerName][0], serverIpList)
+
+def remoteExecuteTcp(serverIpList, requestString):
+ serverStatus = {}
+ serverStatus["ConnectionStatus"] = False
+ serverStatus["ExecutionStatus"] = -1
+ serverStatus["StdOutString"] = None
+ serverStatus["StdErrString"] = None
+ serverStatus["ConnectedIp"] = None
+ serverStatus["Error"] = None
+
+ for ipAddress in serverIpList.values()[0]:
+ try:
+ sock, inputStream, outputStream = Socket.connectToServer(ipAddress)
+ Socket.writePacket(outputStream, requestString)
+ packetString = Socket.readPacket(inputStream)
+ log('__DEBUG__ Received: %s' % repr(packetString))
+ sock.close()
+ serverStatus["ConnectionStatus"] = True
+ serverStatus["ExecutionStatus"] = 0
+ serverStatus["StdOutString"] = packetString
+ serverStatus["StdErrString"] = None
+ serverStatus["ConnectedIp"] = ipAddress
+ serverStatus["Error"] = None
+ return serverStatus
+ except socket.error, e:
+ log("socket error on [%s:%s]: %s" % (serverIpList.keys()[0], ipAddress, str(e)))
+ return serverStatus
+
+def executeRequestCommand(serverList, command, requestDom, cleanupFlag):
+ cleanupStatusDict = {}
+ successStatusDict = {}
+ failureServerList = {}
+ cleanupServerList = {}
+ serverList = deepcopy(serverList)
+
+ statusDict = {}
+ for serverName in serverList.keys():
+ serverStatus = remoteExecuteTcp({serverName : serverList[serverName]}, requestDom.toxml())
+ statusDict[serverName] = serverStatus
+ for serverName in statusDict.keys():
+ statusDict["Response"] = None
+ if statusDict[serverName]["ConnectionStatus"] == True:
+ setLastAccessedNetwork(serverName, statusDict[serverName]["ConnectedIp"])
+ if statusDict[serverName]["ConnectedIp"]:
+ ipList = serverList[serverName]
+ ipList.remove(statusDict[serverName]["ConnectedIp"])
+ cleanupServerList[serverName] = [statusDict[serverName]["ConnectedIp"]] + ipList
+ if statusDict[serverName]["ExecutionStatus"] != 0:
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ responseDom = XDOM()
+ if not responseDom.parseString(statusDict[serverName]["StdOutString"]):
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ statusDict["Response"] = responseDom
+ if "OK" != responseDom.getResponseCode():
+ failureServerList[serverName] = statusDict[serverName]
+ continue
+ successStatusDict[serverName] = statusDict[serverName]
+ if cleanupFlag and failureServerList:
+ rq = deepcopy(requestDom)
+ rq.setRequestAction("cleanup")
+ cleanupStatusDict = {}
+ for serverName in cleanupServerList.keys():
+ serverStatus = remoteExecuteTcp({serverName : cleanupServerList[serverName]}, rq.toxml())
+ cleanupStatusDict[serverName] = serverStatus
+ return successStatusDict, failureServerList, cleanupStatusDict
+
+def preExecute(serverList, requestDom, cleanupFlag=True):
+ rq = deepcopy(requestDom)
+ rq.setRequestAction("pre")
+ return executeRequestCommand(serverList, SERVER_AGENT_PRE_COMMAND, rq, cleanupFlag)
+
+def execute(serverList, requestDom, cleanupFlag=True):
+ return executeRequestCommand(serverList, SERVER_AGENT_COMMAND, requestDom, cleanupFlag)
+
+def postExecute(serverList, requestDom, cleanupFlag=True):
+ rq = deepcopy(requestDom)
+ rq.setRequestAction("post")
+ return executeRequestCommand(serverList, SERVER_AGENT_POST_COMMAND, rq, cleanupFlag)
+
+def cleanupExecute(serverList, requestDom):
+ rq = deepcopy(requestDom)
+ rq.setRequestAction("cleanup")
+ return executeRequestCommand(serverList, SERVER_AGENT_CLEANUP_COMMAND, rq, False)
diff --git a/src/com.gluster.storage.management.server.scripts/src/server/RequestHandler.py b/src/com.gluster.storage.management.server.scripts/src/server/RequestHandler.py
new file mode 100644
index 00000000..e6fe88ff
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/server/RequestHandler.py
@@ -0,0 +1,58 @@
+import os
+import glob
+#import paramiko
+import tempfile
+#import uuid
+import socket
+import tarfile
+import time
+import Globals
+import Commands
+from Protocol import *
+from RemoteExecute import *
+from NetworkUtils import *
+
+def handleRequestGetServerNetworkConfig(requestDom):
+ messageId = requestDom.getAttribute("id")
+ serverName = requestDom.getTextByTagRoute("command.server-name")
+ version = requestDom.getVersion()
+ request = requestDom.getAttribute("request")
+
+ if not serverName:
+ responseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG, "No server name given", messageId, version)
+ responseDom.appendTagRoute("server.name", serverName)
+ return responseDom
+
+ #serverIpList = getExecuteServerList([serverName])
+ #if not serverIpList:
+ # responseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG, "Unable to get server ip", messageId, version)
+ # responseDom.appendTagRoute("server.name", serverName)
+ # return responseDom
+
+ successStatusDict, failureServerList, cleanupStatusDict = \
+ execute({serverName:[serverName]}, requestDom, Globals.REQUEST_MAP[request]["cleanup"])
+ if failureServerList:
+ response = failureServerList[serverName]["StdOutString"]
+ if not response:
+ return ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG,
+ "Failed to execute get server network config", messageId, version)
+ responseDom = XDOM()
+ if responseDom.parseString(response):
+ return responseDom
+ errorResponseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG,
+ "Invalid response of get server network config", messageId, version)
+ errorResponseDom.appendTagRoute("server.name", serverName)
+ return errorResponseDom
+
+ responseDom = XDOM()
+ if not responseDom.parseString(successStatusDict[serverName]["StdOutString"]):
+ errorResponseDom = ResponseXml(Commands.COMMAND_GET_SERVER_NETWORK_CONFIG,
+ "Invalid response of get server network config", messageId, version)
+ errorResponseDom.appendTagRoute("server.name", serverName)
+ return errorResponseDom
+
+ #configDom = getServerNetworkConfigFromLocalFile(serverName)
+ #if not (configDom and compareServerNetworkDom(configDom, responseDom)):
+ # updateServerNetworkConfigXmlFile(serverName, responseDom)
+ # syncConfiguration()
+ return responseDom
diff --git a/src/com.gluster.storage.management.server.scripts/src/server/TransportAgent.py b/src/com.gluster.storage.management.server.scripts/src/server/TransportAgent.py
new file mode 100644
index 00000000..5f39b585
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/server/TransportAgent.py
@@ -0,0 +1,26 @@
+import Commands
+#from Common import log
+from Protocol import *
+from RequestHandler import *
+
+def processRequest(requestDom):
+ Globals.REQUEST_MAP = {
+ Commands.COMMAND_GET_SERVER_NETWORK_CONFIG : {"handle":handleRequestGetServerNetworkConfig,
+ "pre-run":False, "run":True, "post-run":False, \
+ "cleanup":False, "sync-config":False, "safemode":False}}
+
+ messageId = requestDom.getMessageId()
+ if not messageId:
+ log("invalid message from web agent")
+ return None
+
+ requestCommand = requestDom.getRequestCommand()
+ if not requestCommand:
+ log("invalid request from web agent")
+ return None
+
+ try:
+ requestCommand = Globals.REQUEST_MAP[requestCommand]['handle']
+ except KeyError: # Handler not found!
+ return ResponseXml(requestCommand, "Invalid command", messageId, version)
+ return requestCommand(requestDom)
diff --git a/src/com.gluster.storage.management.server.scripts/src/server/transport.py b/src/com.gluster.storage.management.server.scripts/src/server/transport.py
new file mode 100755
index 00000000..9255ff40
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/server/transport.py
@@ -0,0 +1,94 @@
+#!/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 syslog
+import signal
+import datetime
+from Globals import *
+from Protocol import *
+from TransportAgent import *
+from optparse import OptionParser
+
+class TimeoutException(Exception):
+ pass
+
+def timeoutSignal(signum, frame):
+ raise TimeoutException, "Timed out"
+
+def main():
+ openLog(Globals.TRANSPORT_AGENT_LOG_FILE)
+ parser = OptionParser(version="%transport " + Globals.GLUSTER_PLATFORM_VERSION)
+ parser.add_option("-f", "--force",
+ action="store_true", dest="force", default=False,
+ help="Execute command forcefully")
+
+ parser.add_option("-t", "--timeout",
+ type="int", nargs=1, dest="timeout",
+ help="Session time-out")
+
+ parser.add_option("--debug",
+ action="store_true", dest="debug", default=False,
+ help="Enable debug mode")
+ (options, args) = parser.parse_args()
+ Globals.GLUSTER_DEBUG = options.debug
+
+ if len(args) != 1:
+ #print "usage: Transport.py [-f | --force] [-t N | --timeout=N] [--debug] <input-file>"
+ log(syslog.LOG_ERR, "invalid arguments")
+ sys.exit(-1)
+
+ signal.signal(signal.SIGALRM, timeoutSignal)
+ signal.alarm(options.timeout)
+ inputFile = args[0]
+ #outputFile = args[1]
+ try:
+ requestString = open(inputFile).read()
+ if not requestString:
+ sys.exit(-1)
+ fp = open("/tmp/transport.log", "a")
+ fp.write("\n%s: Send: %s\n" % (str(datetime.now()), requestString))
+ fp.close()
+ except IOError:
+ log(syslog.LOG_ERR, "Unable to read input xml file %s" % inputFile)
+ sys.exit(-1)
+
+ requestDom = RequestXml(requestString)
+ if not requestDom:
+ log(syslog.LOG_ERR, "error: invalid request: %s" % requestString)
+ sys.exit(-1)
+
+ responseDom = processRequest(requestDom)
+ if not responseDom:
+ log(syslog.LOG_ERR, "command execution failed")
+ sys.exit(-1)
+
+ #fp = open("/tmp/transport.log", "a")
+ #fp.write("%s: Receive: %s\n" % (str(datetime.now()), responseDom.toxml()))
+ #fp.close()
+
+ #responseDom.writexml(outputFile)
+ print responseDom.toxml()
+ sys.exit(0)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except TimeoutException:
+ log(syslog.LOG_ERR, "session timed out")
+ sys.exit(-1)
diff --git a/src/com.gluster.storage.management.server.scripts/src/server/vmware-discover-servers.py b/src/com.gluster.storage.management.server.scripts/src/server/vmware-discover-servers.py
new file mode 100755
index 00000000..6ac15fed
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/server/vmware-discover-servers.py
@@ -0,0 +1,83 @@
+#!/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 signal
+import struct
+import syslog
+import Globals
+import Common
+
+class TimeoutException(Exception):
+ pass
+
+def timeoutSignal(signum, frame):
+ raise TimeoutException, "Timed out"
+
+def serverDiscoveryRequest(multiCastGroup, port):
+ servers = []
+ # Sending request to all the servers
+ socketSend = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketSend.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
+ socketSend.sendto("ServerDiscovery", (multiCastGroup, port))
+
+ # Waiting for the response
+ socketReceive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketReceive.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ socketReceive.bind(('', port))
+ mreq = struct.pack("4sl", socket.inet_aton(multiCastGroup), socket.INADDR_ANY)
+
+ socketReceive.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+ socketSend.sendto("ServerDiscovery", (multiCastGroup, port))
+
+ try:
+ while True:
+ response = socketReceive.recvfrom(200)
+ if response and response[0].upper() != "SERVERDISCOVERY":
+ servers.append(response[0])
+ signal.signal(signal.SIGALRM, timeoutSignal)
+ signal.alarm(3)
+ except TimeoutException:
+ return servers
+ return None
+
+def main():
+ syslog.openlog("discovery server request")
+ servers = serverDiscoveryRequest(Globals.MULTICAST_GROUP, Globals.MULTICAST_PORT)
+ if not servers:
+ Common.log(syslog.LOG_ERR, "Failed to discover new servers")
+ sys.exit(-1)
+
+ servers = set(servers)
+ try:
+ #fp = open(Globals.DISCOVERED_SERVER_LIST_FILENAME, "w")
+ #fp.writelines(list(servers))
+ #fp.close()
+ for server in servers:
+ print server
+ except IOError:
+ Common.log(syslog.LOG_ERR, "Unable to open file %s" % Globals.DISCOVERED_SERVER_LIST_FILENAME)
+ sys.exit(-1)
+
+ #for serverName in servers:
+ # print serverName
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()