From e40556bdf8fd27e35878a8c1942573da46204b7e Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Fri, 25 Mar 2011 15:43:32 +0530 Subject: Server agent and transport agent --- .../src/nodes/Agent.py | 118 +++++++ .../src/nodes/GetServerNetworkConfig.py | 96 ++++++ .../src/nodes/ServerAgent.py | 179 +++++++++++ .../src/nodes/ServerRequestHandler.py | 76 +++++ .../src/nodes/ServerUtils.py | 308 ++++++++++++++++++ .../src/nodes/Socket.py | 47 +++ .../src/nodes/XmlHandler.py | 346 +++++++++++++++++++++ .../src/nodes/multicast_response.py | 45 +++ 8 files changed, 1215 insertions(+) create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/Agent.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/GetServerNetworkConfig.py create mode 100755 com.gluster.storage.management.server.scripts/src/nodes/ServerAgent.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/ServerRequestHandler.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/ServerUtils.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/Socket.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/XmlHandler.py create mode 100644 com.gluster.storage.management.server.scripts/src/nodes/multicast_response.py (limited to 'com.gluster.storage.management.server.scripts/src/nodes') 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. +# 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 +# . + +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. +# 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 +# . + +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 = """ +s1""" + 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. +# 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 +# . + +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. +# 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 +# . + +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. +# 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 +# . + +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. +# 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 +# . + +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. +# 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 +# . + +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() -- cgit