summaryrefslogtreecommitdiffstats
path: root/com.gluster.storage.management.server.scripts/src/nodes
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-03-25 15:43:32 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-03-25 15:43:32 +0530
commite40556bdf8fd27e35878a8c1942573da46204b7e (patch)
treeb4cf1ec243bf13aee4269981d8f8aeeaa57f1c15 /com.gluster.storage.management.server.scripts/src/nodes
parent9e2122cf8ae1273bb8cdcbcc0f8fb2176f14a428 (diff)
Server agent and transport agent
Diffstat (limited to 'com.gluster.storage.management.server.scripts/src/nodes')
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/Agent.py118
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py96
-rwxr-xr-xcom.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py179
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py76
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py308
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/Socket.py47
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py346
-rw-r--r--com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py45
8 files changed, 1215 insertions, 0 deletions
diff --git a/com.gluster.storage.management.server.scripts/src/nodes/Agent.py b/com.gluster.storage.management.server.scripts/src/nodes/Agent.py
new file mode 100644
index 00000000..6d867d9e
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py b/com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py
new file mode 100644
index 00000000..3311eb56
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py b/com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py
new file mode 100755
index 00000000..bcb2bac1
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py b/com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py
new file mode 100644
index 00000000..31d4eb8c
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py b/com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py
new file mode 100644
index 00000000..1fec994c
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/Socket.py b/com.gluster.storage.management.server.scripts/src/nodes/Socket.py
new file mode 100644
index 00000000..ba6b6ad0
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py b/com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py
new file mode 100644
index 00000000..d5a1fe19
--- /dev/null
+++ b/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/com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py b/com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py
new file mode 100644
index 00000000..64bc0899
--- /dev/null
+++ b/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()