From 5c39a47fdd3987bb5eee35f7f7397ce127c8919e Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Tue, 29 Mar 2011 21:53:36 +0530 Subject: Remote execution of scripts on peer machines from management server --- .../src/common/Globals.py | 5 +- .../src/nodes/PeerAgent.py | 198 +++++++++++++++++++++ .../management/server/utils/ServerUtil.java | 42 +++++ 3 files changed, 243 insertions(+), 2 deletions(-) create mode 100755 src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py (limited to 'src') 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 index 365d4af7..9ae53491 100644 --- a/src/com.gluster.storage.management.server.scripts/src/common/Globals.py +++ b/src/com.gluster.storage.management.server.scripts/src/common/Globals.py @@ -52,7 +52,7 @@ SERVER_AGENT_PORT = 50000 BOOT_PARTITION_LABEL = "GLUSTEROS" DATA_PARTITION_LABEL = "GLUSTERDATA" VOLUME_USER_DESCRIPTION = "Gluster Volume User" -SERVER_AGENT_RUN_USERNAME = "transport" +SERVER_AGENT_RUN_USERNAME = "gluster" INSTALLER_SERVER_NAME = "$installer$" GLUSTER_BASE_DIR = "/GLUSTER" @@ -64,7 +64,7 @@ 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" +LOG_DIR = "/var/log/glustermc" GLUSTER_UPDATES_FILE = "updates.xml" INSTALLER_STATUS_FILE = "/var/log/install-server-status.log" @@ -103,6 +103,7 @@ SESSION_FILE = GLUSTER_TMP_DIR + "/login.sessions" GENERAL_LOG_FILE = LOG_DIR + "/general.log" INSTALLER_LOG_FILE = LOG_DIR + "/installer.log" +PEER_AGENT_LOG_FILE = LOG_DIR + "/peeragent.log" SERVER_AGENT_LOG_FILE = LOG_DIR + "/serveragent.log" TRANSPORT_AGENT_LOG_FILE = LOG_DIR + "/transport.log" ## diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py b/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py new file mode 100755 index 00000000..93c1f002 --- /dev/null +++ b/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py @@ -0,0 +1,198 @@ +#!/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 +from XmlHandler import ResponseXml + + +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 stripEmptyLines(content): + ret = "" + for line in content.split("\n"): + if line.strip() != "": + ret += line + return ret + +def executeCommand(command): + rv = Utils.runCommandFG(command, stdout=True, root=True) + statusCode = rv["Status"] + if statusCode != 0: + rs = ResponseXml() + rs.appendTagRoute("status", statusCode); + rs.appendTagRoute("output", stripEmptyLines(rv["Stdout"])) + rs.appendTagRoute("error", stripEmptyLines(rv["Stderr"])) + print rs.toprettyxml() + return rs.toprettyxml() + else: + return rv["Stdout"] + +def main(): + global PID_FILE + global serverSocket + global clientSocket + global clientAddress + global clientInputStream + global clientOutputStream + + username = Globals.SERVER_AGENT_RUN_USERNAME + + Utils.openLog(Globals.PEER_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 = executeCommand(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/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java index 1d237461..b07873f1 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java @@ -20,6 +20,11 @@ */ package com.gluster.storage.management.server.utils; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.Socket; import java.util.ArrayList; import java.util.List; @@ -55,4 +60,41 @@ public class ServerUtil { String scriptPath = servletContext.getRealPath(SCRIPT_DIR) + CoreConstants.FILE_SEPARATOR + scriptName; return scriptPath; } + + /** + * Executes given command on given server + * + * @param runInForeground + * @param serverName + * @param commandWithArgs + * @return Response from remote execution of the command + */ + public String executeOnServer(boolean runInForeground, String serverName, String commandWithArgs) { + try { + InetAddress address = InetAddress.getByName(serverName); + Socket connection = new Socket(address, 50000); + + PrintWriter writer = new PrintWriter(connection.getOutputStream(), true); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); + + writer.println(commandWithArgs); + writer.println(); // empty line means end of request + + StringBuffer output = new StringBuffer(); + String line; + while (!(line = reader.readLine()).trim().isEmpty()) { + output.append(line + CoreConstants.NEWLINE); + } + + connection.close(); + return output.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String args[]) { + System.out.println(new ServerUtil().executeOnServer(true, "localhost", "ls -lrt")); + } } \ No newline at end of file -- cgit