summaryrefslogtreecommitdiffstats
path: root/func/minion
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2008-02-07 13:13:24 -0500
committerMichael DeHaan <mdehaan@redhat.com>2008-02-07 13:13:24 -0500
commit8f2ff4d7c902d534d68ff1a16418b7be492033bf (patch)
tree73cd958ea6f8e0728592fec759848280b8891f12 /func/minion
parent5b2601a56907b02efc6567354fa051ef08d97b6f (diff)
downloadcertmaster-8f2ff4d7c902d534d68ff1a16418b7be492033bf.tar.gz
certmaster-8f2ff4d7c902d534d68ff1a16418b7be492033bf.tar.xz
certmaster-8f2ff4d7c902d534d68ff1a16418b7be492033bf.zip
Carving away at func some more to just get down to cert items, still lots
more to do.
Diffstat (limited to 'func/minion')
-rw-r--r--func/minion/AuthedXMLRPCServer.py140
-rwxr-xr-xfunc/minion/Makefile24
-rw-r--r--func/minion/__init__.py0
-rwxr-xr-xfunc/minion/codes.py29
-rwxr-xr-xfunc/minion/module_loader.py118
-rwxr-xr-xfunc/minion/modules/Makefile18
-rw-r--r--func/minion/modules/__init__.py0
-rw-r--r--func/minion/modules/certmaster.py65
-rw-r--r--func/minion/modules/command.py44
-rw-r--r--func/minion/modules/copyfile.py109
-rw-r--r--func/minion/modules/filetracker.py192
-rw-r--r--func/minion/modules/func_module.py76
-rw-r--r--func/minion/modules/func_module.py.orig65
-rw-r--r--func/minion/modules/hardware.py130
-rw-r--r--func/minion/modules/jobs.py36
-rw-r--r--func/minion/modules/mount.py84
-rw-r--r--func/minion/modules/nagios-check.py34
-rw-r--r--func/minion/modules/netapp/README8
-rw-r--r--func/minion/modules/netapp/TODO5
-rw-r--r--func/minion/modules/netapp/__init__.py0
-rw-r--r--func/minion/modules/netapp/common.py49
-rw-r--r--func/minion/modules/netapp/snap.py49
-rw-r--r--func/minion/modules/netapp/vol/__init__.py128
-rw-r--r--func/minion/modules/netapp/vol/clone.py46
-rw-r--r--func/minion/modules/networktest.py64
-rw-r--r--func/minion/modules/process.py216
-rw-r--r--func/minion/modules/process.py.orig221
-rw-r--r--func/minion/modules/reboot.py21
-rw-r--r--func/minion/modules/rpms.py44
-rw-r--r--func/minion/modules/service.py88
-rw-r--r--func/minion/modules/smart.py47
-rw-r--r--func/minion/modules/snmp.py38
-rw-r--r--func/minion/modules/sysctl.py31
-rw-r--r--func/minion/modules/test.py29
-rw-r--r--func/minion/modules/virt.py277
-rw-r--r--func/minion/modules/yumcmd.py50
-rwxr-xr-xfunc/minion/server.py285
-rw-r--r--func/minion/sub_process.py1221
-rwxr-xr-xfunc/minion/utils.py207
39 files changed, 0 insertions, 4288 deletions
diff --git a/func/minion/AuthedXMLRPCServer.py b/func/minion/AuthedXMLRPCServer.py
deleted file mode 100644
index 0ec9ce0..0000000
--- a/func/minion/AuthedXMLRPCServer.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# This program 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 2 of the License, or
-# (at your option) any later version.
-#
-# This program 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 Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
-# Modifications by Seth Vidal - 2007
-
-import sys
-import socket
-import SimpleXMLRPCServer
-from func import SSLCommon
-import OpenSSL
-import SocketServer
-
-
-class AuthedSimpleXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
-
- # For some reason, httplib closes the connection right after headers
- # have been sent if the connection is _not_ HTTP/1.1, which results in
- # a "Bad file descriptor" error when the client tries to read from the socket
- protocol_version = "HTTP/1.1"
-
- def setup(self):
- """
- We need to use socket._fileobject Because SSL.Connection
- doesn't have a 'dup'. Not exactly sure WHY this is, but
- this is backed up by comments in socket.py and SSL/connection.c
- """
- self.connection = self.request # for doPOST
- self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
- self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
-
- def do_POST(self):
- self.server._this_request = (self.request, self.client_address)
- try:
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
- except socket.timeout:
- pass
- except (socket.error, OpenSSL.SSL.SysCallError), e:
- print "Error (%s): socket error - '%s'" % (self.client_address, e)
-
-
-class BaseAuthedXMLRPCServer(SocketServer.ThreadingMixIn):
- def __init__(self, address, authinfo_callback=None):
- self.allow_reuse_address = 1
- self.logRequests = 1
- self.authinfo_callback = authinfo_callback
-
- self.funcs = {}
- self.instance = None
-
- def get_authinfo(self, request, client_address):
- print 'down here'
- if self.authinfo_callback:
- return self.authinfo_callback(request, client_address)
- return None
-
-
-class AuthedSSLXMLRPCServer(BaseAuthedXMLRPCServer, SSLCommon.BaseSSLServer, SimpleXMLRPCServer.SimpleXMLRPCServer):
- """ Extension to allow more fine-tuned SSL handling """
-
- def __init__(self, address, pkey, cert, ca_cert, authinfo_callback=None, timeout=None):
- BaseAuthedXMLRPCServer.__init__(self, address, authinfo_callback)
- SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler)
- SSLCommon.BaseSSLServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler, pkey, cert, ca_cert, timeout=timeout)
-
-
-
-class AuthedXMLRPCServer(BaseAuthedXMLRPCServer, SSLCommon.BaseServer, SimpleXMLRPCServer.SimpleXMLRPCServer):
-
- def __init__(self, address, authinfo_callback=None):
- BaseAuthedXMLRPCServer.__init__(self, address, authinfo_callback)
- SSLCommon.BaseServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler)
-
-
-###########################################################
-# Testing stuff
-###########################################################
-
-class ReqHandler:
- def ping(self, callerid, trynum):
- print 'clearly not'
- print callerid
- print trynum
- return "pong %d / %d" % (callerid, trynum)
-
-class TestServer(AuthedSSLXMLRPCServer):
- """
- SSL XMLRPC server that authenticates clients based on their certificate.
- """
-
- def __init__(self, address, pkey, cert, ca_cert):
- AuthedSSLXMLRPCServer.__init__(self, address, pkey, cert, ca_cert, self.auth_cb)
-
- def _dispatch(self, method, params):
- if method == 'trait_names' or method == '_getAttributeNames':
- return dir(self)
- # if we have _this_request then we get the peer cert from it
- # handling all the authZ checks in _dispatch() means we don't even call the method
- # for whatever it wants to do and we have the method name.
-
- if hasattr(self, '_this_request'):
- r,a = self._this_request
- p = r.get_peer_certificate()
- print dir(p)
- print p.get_subject()
- else:
- print 'no cert'
-
- return "your mom"
-
- def auth_cb(self, request, client_address):
- peer_cert = request.get_peer_certificate()
- return peer_cert.get_subject().CN
-
-
-if __name__ == '__main__':
- if len(sys.argv) < 4:
- print "Usage: python AuthdXMLRPCServer.py key cert ca_cert"
- sys.exit(1)
-
- pkey = sys.argv[1]
- cert = sys.argv[2]
- ca_cert = sys.argv[3]
-
- print "Starting the server."
- server = TestServer(('localhost', 51234), pkey, cert, ca_cert)
- h = ReqHandler()
- server.register_instance(h)
- server.serve_forever()
diff --git a/func/minion/Makefile b/func/minion/Makefile
deleted file mode 100755
index d630382..0000000
--- a/func/minion/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-PYFILES = $(wildcard *.py)
-PYDIRS = modules
-
-PYCHECKER = /usr/bin/pychecker
-PYFLAKES = /usr/bin/pyflakes
-
-clean::
- @rm -fv *.pyc *~ .*~ *.pyo
- @find . -name .\#\* -exec rm -fv {} \;
- @rm -fv *.rpm
-
-
-pychecker::
- @$(PYCHECKER) $(PYFILES) || exit 0
-
-pyflakes::
- @$(PYFLAKES) $(PYFILES) || exit 0
-
-pychecker::
- -for d in $(PYDIRS); do ($(MAKE) -C $$d pychecker ); done
-pyflakes::
- -for d in $(PYDIRS); do ($(MAKE) -C $$d pyflakes ); done
diff --git a/func/minion/__init__.py b/func/minion/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/func/minion/__init__.py
+++ /dev/null
diff --git a/func/minion/codes.py b/func/minion/codes.py
deleted file mode 100755
index a20c95e..0000000
--- a/func/minion/codes.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""
-func
-
-Copyright 2007, Red Hat, Inc
-See AUTHORS
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-import exceptions
-
-
-class FuncException(exceptions.Exception):
- pass
-
-
-class InvalidMethodException(FuncException):
- pass
-
-
-class AccessToMethodDenied(FuncException):
- pass
-
-# FIXME: more sub-exceptions maybe
diff --git a/func/minion/module_loader.py b/func/minion/module_loader.py
deleted file mode 100755
index 3068ea8..0000000
--- a/func/minion/module_loader.py
+++ /dev/null
@@ -1,118 +0,0 @@
-## func
-##
-## Copyright 2007, Red Hat, Inc
-## See AUTHORS
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-##
-
-
-import distutils.sysconfig
-import os
-import sys
-from gettext import gettext
-_ = gettext
-
-from func import logger
-logger = logger.Logger().logger
-
-from inspect import isclass
-from func.minion.modules import func_module
-
-def module_walker(topdir):
- module_files = []
- for root, dirs, files in os.walk(topdir):
- # we should get here for each subdir
- for filename in files:
- # ASSUMPTION: all module files will end with .py, .pyc, .pyo
- if filename[-3:] == ".py" or filename[-4:] == ".pyc" or filename[-4:] == ".pyo":
- # the normpath is important, since we eventually replace /'s with .'s
- # in the module name, and foo..bar doesnt work -akl
- module_files.append(os.path.normpath("%s/%s" % (root, filename)))
-
-
- return module_files
-
-def load_modules(blacklist=None):
-
- module_file_path="%s/func/minion/modules/" % distutils.sysconfig.get_python_lib()
- mod_path="%s/func/minion/" % distutils.sysconfig.get_python_lib()
-
- sys.path.insert(0, mod_path)
- mods = {}
- bad_mods = {}
-
- filenames = module_walker(module_file_path)
-
- # FIXME: this is probably more complicated than it needs to be -akl
- for fn in filenames:
- # aka, everything after the module_file_path
- module_name_part = fn[len(module_file_path):]
- dirname, basename = os.path.split(module_name_part)
-
- if basename[:8] == "__init__":
- modname = dirname
- dirname = ""
- elif basename[-3:] == ".py":
- modname = basename[:-3]
- elif basename[-4:] in [".pyc", ".pyo"]:
- modname = basename[:-4]
-
- pathname = modname
- if dirname != "":
- pathname = "%s/%s" % (dirname, modname)
-
- mod_imp_name = pathname.replace("/", ".")
-
- if mods.has_key(mod_imp_name):
- # If we've already imported mod_imp_name, don't import it again
- continue
-
- # ignore modules that we've already determined aren't valid modules
- if bad_mods.has_key(mod_imp_name):
- continue
-
- try:
- # Auto-detect and load all FuncModules
- blip = __import__("modules.%s" % ( mod_imp_name), globals(), locals(), [mod_imp_name])
- for obj in dir(blip):
- attr = getattr(blip, obj)
- if isclass(attr) and issubclass(attr, func_module.FuncModule):
- logger.debug("Loading %s module" % attr)
- mods[mod_imp_name] = attr()
-
- except ImportError, e:
- # A module that raises an ImportError is (for now) simply not loaded.
- errmsg = _("Could not load %s module: %s")
- logger.warning(errmsg % (mod_imp_name, e))
- bad_mods[mod_imp_name] = True
- continue
- except:
- errmsg = _("Could not load %s module")
- logger.warning(errmsg % (mod_imp_name))
- bad_mods[mod_imp_name] = True
- continue
-
- return mods
-
-
-if __name__ == "__main__":
-
- module_file_path = "/usr/lib/python2.5/site-packages/func/minion/modules/"
- bar = module_walker(module_file_path)
- print bar
- for f in bar:
- print f
- print os.path.basename(f)
- print os.path.split(f)
- g = f[len(module_file_path):]
- print g
- print os.path.split(g)
-
- print load_modules()
diff --git a/func/minion/modules/Makefile b/func/minion/modules/Makefile
deleted file mode 100755
index f2bc6c4..0000000
--- a/func/minion/modules/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-PYFILES = $(wildcard *.py)
-
-PYCHECKER = /usr/bin/pychecker
-PYFLAKES = /usr/bin/pyflakes
-
-clean::
- @rm -fv *.pyc *~ .*~ *.pyo
- @find . -name .\#\* -exec rm -fv {} \;
- @rm -fv *.rpm
-
-
-pychecker::
- @$(PYCHECKER) $(PYFILES) || exit 0
-
-pyflakes::
- @$(PYFLAKES) $(PYFILES) || exit 0
diff --git a/func/minion/modules/__init__.py b/func/minion/modules/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/func/minion/modules/__init__.py
+++ /dev/null
diff --git a/func/minion/modules/certmaster.py b/func/minion/modules/certmaster.py
deleted file mode 100644
index 9ca484f..0000000
--- a/func/minion/modules/certmaster.py
+++ /dev/null
@@ -1,65 +0,0 @@
-## -*- coding: utf-8 -*-
-##
-## Process lister (control TBA)
-##
-## Copyright 2008, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-# other modules
-import sub_process
-import codes
-
-# our modules
-import func_module
-from func import certmaster as certmaster
-
-# =================================
-
-class CertMasterModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Administers certs on an overlord."
-
- def get_hosts_to_sign(self, list_of_hosts):
- """
- ...
- """
- list_of_hosts = self.__listify(list_of_hosts)
- cm = certmaster.CertMaster()
- return cm.get_csrs_waiting()
-
- def sign_hosts(self, list_of_hosts):
- """
- ...
- """
- list_of_hosts = self.__listify(list_of_hosts)
- cm = certmaster.CertMaster()
- for x in list_of_hosts:
- cm.sign_this_csr(x)
- return True
-
- def cleanup_hosts(self, list_of_hosts):
- """
- ...
- """
- list_of_hosts = self.__listify(list_of_hosts)
- cm = certmaster.CertMaster()
- for x in list_of_hosts:
- cm.remove_this_cert(x)
- return True
-
- def __listify(self, list_of_hosts):
- if type(list_of_hosts) is type([]):
- return list_of_hosts
- else:
- return [ list_of_hosts ]
-
diff --git a/func/minion/modules/command.py b/func/minion/modules/command.py
deleted file mode 100644
index cc463cf..0000000
--- a/func/minion/modules/command.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# James Bowes <jbowes@redhat.com>
-# Steve 'Ashcrow' Milner <smilner@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-"""
-Abitrary command execution module for func.
-"""
-
-import func_module
-import sub_process
-
-class Command(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Works with shell commands."
-
- def run(self, command):
- """
- Runs a command, returning the return code, stdout, and stderr as a tuple.
- NOT FOR USE WITH INTERACTIVE COMMANDS.
- """
-
- cmdref = sub_process.Popen(command.split(), stdout=sub_process.PIPE,
- stderr=sub_process.PIPE, shell=False)
- data = cmdref.communicate()
- return (cmdref.returncode, data[0], data[1])
-
- def exists(self, command):
- """
- Checks to see if a command exists on the target system(s).
- """
- import os
-
- if os.access(command, os.X_OK):
- return True
- return False
diff --git a/func/minion/modules/copyfile.py b/func/minion/modules/copyfile.py
deleted file mode 100644
index 150af88..0000000
--- a/func/minion/modules/copyfile.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# seth vidal
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-import sha
-import os
-import time
-import shutil
-
-import func_module
-
-
-class CopyFile(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.2"
- description = "Allows for smart copying of a file."
-
- def _checksum_blob(self, blob):
- thissum = sha.new()
- thissum.update(blob)
- return thissum.hexdigest()
-
- def checksum(self, thing):
-
- CHUNK=2**16
- thissum = sha.new()
- if os.path.exists(thing):
- fo = open(thing, 'r', CHUNK)
- chunk = fo.read
- while chunk:
- chunk = fo.read(CHUNK)
- thissum.update(chunk)
- fo.close()
- del fo
- else:
- # assuming it's a string of some kind
- thissum.update(thing)
-
- return thissum.hexdigest()
-
-
- def copyfile(self, filepath, filebuf, mode=0644, uid=0, gid=0, force=None):
- # -1 = problem file was not copied
- # 1 = file was copied
- # 0 = file was not copied b/c file is unchanged
-
-
- # we should probably verify mode,uid,gid are valid as well
-
- dirpath = os.path.dirname(filepath)
- if not os.path.exists(dirpath):
- os.makedirs(dirpath)
-
- remote_sum = self._checksum_blob(filebuf.data)
- local_sum = 0
- if os.path.exists(filepath):
- local_sum = self.checksum(filepath)
-
- if remote_sum != local_sum or force is not None:
- # back up the localone
- if os.path.exists(filepath):
- if not self._backuplocal(filepath):
- return -1
-
- # do the new write
- try:
- fo = open(filepath, 'w')
- fo.write(filebuf.data)
- fo.close()
- del fo
- except (IOError, OSError), e:
- # XXX logger output here
- return -1
- else:
- return 0
-
- # hmm, need to figure out proper exceptions -akl
- try:
- # we could intify the mode here if it's a string
- os.chmod(filepath, mode)
- os.chown(filepath, uid, gid)
- except (IOError, OSError), e:
- return -1
-
- return 1
-
- def _backuplocal(self, fn):
- """
- make a date-marked backup of the specified file,
- return True or False on success or failure
- """
- # backups named basename-YYYY-MM-DD@HH:MM~
- ext = time.strftime("%Y-%m-%d@%H:%M~", time.localtime(time.time()))
- backupdest = '%s.%s' % (fn, ext)
-
- try:
- shutil.copy2(fn, backupdest)
- except shutil.Error, e:
- #XXX logger output here
- return False
- return True
diff --git a/func/minion/modules/filetracker.py b/func/minion/modules/filetracker.py
deleted file mode 100644
index f5f9dbb..0000000
--- a/func/minion/modules/filetracker.py
+++ /dev/null
@@ -1,192 +0,0 @@
-## func
-##
-## filetracker
-## maintains a manifest of files of which to keep track
-## provides file meta-data (and optionally full data) to func-inventory
-##
-## (C) Vito Laurenza <vitolaurenza@gmail.com>
-## + Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-# func modules
-import func_module
-
-# other modules
-from stat import *
-import glob
-import os
-import md5
-
-# defaults
-CONFIG_FILE='/etc/func/modules/filetracker.conf'
-
-class FileTracker(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Maintains a manifest of files to keep track of."
-
- def __load(self):
- """
- Parse file and return data structure.
- """
-
- filehash = {}
- if os.path.exists(CONFIG_FILE):
- config = open(CONFIG_FILE, "r")
- data = config.read()
- lines = data.split("\n")
- for line in lines:
- tokens = line.split(None)
- if len(tokens) < 2:
- continue
- scan_mode = tokens[0]
- path = " ".join(tokens[1:])
- if str(scan_mode).lower() == "0":
- scan_mode = 0
- else:
- scan_mode = 1
- filehash[path] = scan_mode
- return filehash
-
- #==========================================================
-
- def __save(self, filehash):
- """
- Write data structure to file.
- """
-
- config = open(CONFIG_FILE, "w+")
- for (path, scan_mode) in filehash.iteritems():
- config.write("%s %s\n" % (scan_mode, path))
- config.close()
-
- #==========================================================
-
- def track(self, file_name, full_scan=0):
- """
- Adds files to keep track of.
- full_scan implies tracking the full contents of the file, defaults to off
- """
-
- filehash = self.__load()
- filehash[file_name] = full_scan
- self.__save(filehash)
- return 1
-
- #==========================================================
-
- def untrack(self, file_name):
- """
- Stop keeping track of a file.
- This routine is tolerant of most errors since we're forgetting about the file anyway.
- """
-
- filehash = self.__load()
- if file_name in filehash.keys():
- del filehash[file_name]
- self.__save(filehash)
- return 1
-
- #==========================================================
-
- def inventory(self, flatten=1, checksum_enabled=1):
- """
- Returns information on all tracked files
- By default, 'flatten' is passed in as True, which makes printouts very clean in diffs
- for use by func-inventory. If you are writting another software application, using flatten=False will
- prevent the need to parse the returns.
- """
-
- # XMLRPC feeds us strings from the CLI when it shouldn't
- flatten = int(flatten)
- checksum_enabled = int(checksum_enabled)
-
- filehash = self.__load()
-
- # we'll either return a very flat string (for clean diffs)
- # or a data structure
- if flatten:
- results = ""
- else:
- results = []
-
- for (file_name, scan_type) in filehash.iteritems():
-
- if not os.path.exists(file_name):
- if flatten:
- results = results + "%s: does not exist\n" % file_name
- else:
- results.append("%s: does not exist\n" % file_name)
- continue
-
- this_result = []
-
- # ----- always process metadata
- filestat = os.stat(file_name)
- mode = filestat[ST_MODE]
- mtime = filestat[ST_MTIME]
- uid = filestat[ST_UID]
- gid = filestat[ST_GID]
- if not os.path.isdir(file_name) and checksum_enabled:
- sum_handle = open(file_name)
- hash = self.__sumfile(sum_handle)
- sum_handle.close()
- else:
- hash = "N/A"
-
- # ------ what we return depends on flatten
- if flatten:
- this_result = "%s: mode=%s mtime=%s uid=%s gid=%s md5sum=%s\n" % (file_name,mode,mtime,uid,gid,hash)
- else:
- this_result = [file_name,mode,mtime,uid,gid,hash]
-
- # ------ add on file data only if requested
- if scan_type != 0 and os.path.isfile(file_name):
- tracked_file = open(file_name)
- data = tracked_file.read()
- if flatten:
- this_result = this_result + "*** DATA ***\n" + data + "\n*** END DATA ***\n\n"
- else:
- this_result.append(data)
- tracked_file.close()
-
- if os.path.isdir(file_name):
- if not file_name.endswith("/"):
- file_name = file_name + "/"
- files = glob.glob(file_name + "*")
- if flatten:
- this_result = this_result + "*** FILES ***\n" + "\n".join(files) + "\n*** END FILES ***\n\n"
- else:
- this_result.append({"files" : files})
-
- if flatten:
- results = results + "\n" + this_result
- else:
- results.append(this_result)
-
-
- return results
-
- #==========================================================
-
- def __sumfile(self, fobj):
- """
- Returns an md5 hash for an object with read() method.
- credit: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266486
- """
-
- m = md5.new()
- while True:
- d = fobj.read(8096)
- if not d:
- break
- m.update(d)
- return m.hexdigest()
diff --git a/func/minion/modules/func_module.py b/func/minion/modules/func_module.py
deleted file mode 100644
index 7d476dc..0000000
--- a/func/minion/modules/func_module.py
+++ /dev/null
@@ -1,76 +0,0 @@
-##
-## Copyright 2007, Red Hat, Inc
-## see AUTHORS
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import inspect
-
-from func import logger
-from func.config import read_config
-from func.commonconfig import FuncdConfig
-
-
-class FuncModule(object):
-
- # the version is meant to
- version = "0.0.0"
- api_version = "0.0.0"
- description = "No Description provided"
-
- def __init__(self):
-
- config_file = '/etc/func/minion.conf'
- self.config = read_config(config_file, FuncdConfig)
- self.__init_log()
- self.__base_methods = {
- # __'s so we don't clobber useful names
- "module_version" : self.__module_version,
- "module_api_version" : self.__module_api_version,
- "module_description" : self.__module_description,
- "list_methods" : self.__list_methods
- }
-
- def __init_log(self):
- log = logger.Logger()
- self.logger = log.logger
-
- def register_rpc(self, handlers, module_name):
- # add the internal methods, note that this means they
- # can get clobbbered by subclass versions
- for meth in self.__base_methods:
- handlers["%s.%s" % (module_name, meth)] = self.__base_methods[meth]
-
- # register our module's handlers
- for name, handler in self.__list_handlers().items():
- handlers["%s.%s" % (module_name, name)] = handler
-
- def __list_handlers(self):
- """ Return a dict of { handler_name, method, ... }.
- All methods that do not being with an underscore will be exposed.
- We also make sure to not expose our register_rpc method.
- """
- handlers = {}
- for attr in dir(self):
- if inspect.ismethod(getattr(self, attr)) and attr[0] != '_' and \
- attr != 'register_rpc':
- handlers[attr] = getattr(self, attr)
- return handlers
-
- def __list_methods(self):
- return self.__list_handlers().keys() + self.__base_methods.keys()
-
- def __module_version(self):
- return self.version
-
- def __module_api_version(self):
- return self.api_version
-
- def __module_description(self):
- return self.description
diff --git a/func/minion/modules/func_module.py.orig b/func/minion/modules/func_module.py.orig
deleted file mode 100644
index c911b91..0000000
--- a/func/minion/modules/func_module.py.orig
+++ /dev/null
@@ -1,65 +0,0 @@
-##
-## Copyright 2007, Red Hat, Inc
-## see AUTHORS
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import inspect
-
-from func import logger
-from func.config import read_config
-from func.commonconfig import FuncdConfig
-
-
-class FuncModule(object):
-
- # the version is meant to
- version = "0.0.0"
- api_version = "0.0.0"
- description = "No Description provided"
-
- def __init__(self):
-
- config_file = '/etc/func/minion.conf'
- self.config = read_config(config_file, FuncdConfig)
- self.__init_log()
- self.__base_methods = {
- # __'s so we don't clobber useful names
- "module_version" : self.__module_version,
- "module_api_version" : self.__module_api_version,
- "module_description" : self.__module_description,
- "list_methods" : self.__list_methods
- }
-
- def __init_log(self):
- log = logger.Logger()
- self.logger = log.logger
-
- def register_rpc(self, handlers, module_name):
- # add the internal methods, note that this means they
- # can get clobbbered by subclass versions
- for meth in self.__base_methods:
- handlers["%s.%s" % (module_name, meth)] = self.__base_methods[meth]
-
- # register all methods that don't start with an underscore
- for attr in dir(self):
- if inspect.ismethod(getattr(self, attr)) and attr[0] != '_':
- handlers["%s.%s" % (module_name, attr)] = getattr(self, attr)
-
- def __list_methods(self):
- return self.methods.keys() + self.__base_methods.keys()
-
- def __module_version(self):
- return self.version
-
- def __module_api_version(self):
- return self.api_version
-
- def __module_description(self):
- return self.description
diff --git a/func/minion/modules/hardware.py b/func/minion/modules/hardware.py
deleted file mode 100644
index 46b1821..0000000
--- a/func/minion/modules/hardware.py
+++ /dev/null
@@ -1,130 +0,0 @@
-##
-## Hardware profiler plugin
-## requires the "smolt" client package be installed
-## but also relies on lspci for some things
-##
-## Copyright 2007, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-
-# other modules
-import sys
-
-# our modules
-import sub_process
-import func_module
-
-# =================================
-
-class HardwareModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Hardware profiler."
-
- def hal_info(self):
- """
- Returns the output of lshal, but split up into seperate devices
- for easier parsing. Each device is a entry in the return hash.
- """
-
- cmd = sub_process.Popen(["/usr/bin/lshal"],shell=False,stdout=sub_process.PIPE)
- data = cmd.communicate()[0]
-
- data = data.split("\n")
-
- results = {}
- current = ""
- label = data[0]
- for d in data:
- if d == '':
- results[label] = current
- current = ""
- label = ""
- else:
- if label == "":
- label = d
- current = current + d
-
- return results
-
- def inventory(self):
- data = hw_info(with_devices=True)
- # remove bogomips because it keeps changing for laptops
- # and makes inventory tracking noisy
- if data.has_key("bogomips"):
- del data["bogomips"]
- return data
-
- def info(self,with_devices=True):
- """
- Returns a struct of hardware information. By default, this pulls down
- all of the devices. If you don't care about them, set with_devices to
- False.
- """
- return hw_info(with_devices)
-
-# =================================
-
-def hw_info(with_devices=True):
-
- # this may fail if smolt is not installed. That's ok. hal_info will
- # still work.
-
- # hack: smolt is not installed in site-packages
- sys.path.append("/usr/share/smolt/client")
- import smolt
-
- hardware = smolt.Hardware()
- host = hardware.host
-
- # NOTE: casting is needed because these are DBusStrings, not real strings
- data = {
- 'os' : str(host.os),
- 'defaultRunlevel' : str(host.defaultRunlevel),
- 'bogomips' : str(host.bogomips),
- 'cpuVendor' : str(host.cpuVendor),
- 'cpuModel' : str(host.cpuModel),
- 'numCpus' : str(host.numCpus),
- 'cpuSpeed' : str(host.cpuSpeed),
- 'systemMemory' : str(host.systemMemory),
- 'systemSwap' : str(host.systemSwap),
- 'kernelVersion' : str(host.kernelVersion),
- 'language' : str(host.language),
- 'platform' : str(host.platform),
- 'systemVendor' : str(host.systemVendor),
- 'systemModel' : str(host.systemModel),
- 'formfactor' : str(host.formfactor),
- 'selinux_enabled' : str(host.selinux_enabled),
- 'selinux_enforce' : str(host.selinux_enforce)
- }
-
- # if no hardware info requested, just return the above bits
- if not with_devices:
- return data
-
- collection = data["devices"] = []
-
- for item in hardware.deviceIter():
-
- (VendorID,DeviceID,SubsysVendorID,SubsysDeviceID,Bus,Driver,Type,Description) = item
-
- collection.append({
- "VendorID" : str(VendorID),
- "DeviceID" : str(DeviceID),
- "SubsysVendorID" : str(SubsysVendorID),
- "Bus" : str(Bus),
- "Driver" : str(Driver),
- "Type" : str(Type),
- "Description" : str(Description)
- })
-
- return data
diff --git a/func/minion/modules/jobs.py b/func/minion/modules/jobs.py
deleted file mode 100644
index 69fb75f..0000000
--- a/func/minion/modules/jobs.py
+++ /dev/null
@@ -1,36 +0,0 @@
-## (Largely internal) module for access to asynchoronously dispatched
-## module job ID's. The Func Client() module wraps most of this usage
-## so it's not entirely relevant to folks using the CLI or Func API
-## directly.
-##
-## Copyright 2008, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import codes
-from func import jobthing
-import func_module
-
-# =================================
-
-class JobsModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Internal module for tracking background minion tasks."
-
- def job_status(self, job_id):
- """
- Returns job status in the form of (status, datastruct).
- Datastruct is undefined for unfinished jobs. See jobthing.py and
- Wiki details on async invocation for more information.
- """
- return jobthing.job_status(job_id)
-
diff --git a/func/minion/modules/mount.py b/func/minion/modules/mount.py
deleted file mode 100644
index 0db914f..0000000
--- a/func/minion/modules/mount.py
+++ /dev/null
@@ -1,84 +0,0 @@
-##
-## Mount manager
-##
-## Copyright 2007, Red Hat, Inc
-## John Eckersberg <jeckersb@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import sub_process, os
-import func_module
-
-
-class MountModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Mounting, unmounting and getting information on mounted filesystems."
-
- def list(self):
- cmd = sub_process.Popen(["/bin/cat", "/proc/mounts"], executable="/bin/cat", stdout=sub_process.PIPE, shell=False)
- data = cmd.communicate()[0]
-
- mounts = []
- lines = [l for l in data.split("\n") if l] #why must you append blank crap?
-
- for line in lines:
- curmount = {}
- tokens = line.split()
- curmount['device'] = tokens[0]
- curmount['dir'] = tokens[1]
- curmount['type'] = tokens[2]
- curmount['options'] = tokens[3]
- mounts.append(curmount)
-
- return mounts
-
- def mount(self, device, dir, type="auto", options=None, createdir=False):
- cmdline = ["/bin/mount", "-t", type]
- if options:
- cmdline.append("-o")
- cmdline.append(options)
- cmdline.append(device)
- cmdline.append(dir)
- if createdir:
- try:
- os.makedirs(dir)
- except:
- return False
- cmd = sub_process.Popen(cmdline, executable="/bin/mount", stdout=sub_process.PIPE, shell=False)
- if cmd.wait() == 0:
- return True
- else:
- return False
-
- def umount(self, dir, killall=False, force=False, lazy=False):
- # succeed if its not mounted
- if not os.path.ismount(dir):
- return True
-
- if killall:
- cmd = sub_process.Popen(["/sbin/fuser", "-mk", dir], executable="/sbin/fuser", stdout=sub_process.PIPE, shell=False)
- cmd.wait()
-
- cmdline = ["/bin/umount"]
- if force:
- cmdline.append("-f")
- if lazy:
- cmdline.append("-l")
- cmdline.append(dir)
-
- cmd = sub_process.Popen(cmdline, executable="/bin/umount", stdout=sub_process.PIPE, shell=False)
- if cmd.wait() == 0:
- return True
- else:
- return False
-
- def inventory(self, flatten=True):
- return self.list()
diff --git a/func/minion/modules/nagios-check.py b/func/minion/modules/nagios-check.py
deleted file mode 100644
index f1c0714..0000000
--- a/func/minion/modules/nagios-check.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# James Bowes <jbowes@redhat.com>
-# Seth Vidal modified command.py to be nagios-check.py
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-"""
-Abitrary command execution module for func.
-"""
-
-import func_module
-import sub_process
-
-class Nagios(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Runs nagios checks."
-
- def run(self, check_command):
- """
- Runs a nagios check returning the return code, stdout, and stderr as a tuple.
- """
- nagios_path='/usr/lib/nagios/plugins'
- command = '%s/%s' % (nagios_path, check_command)
-
- cmdref = sub_process.Popen(command.split(),stdout=sub_process.PIPE,stderr=sub_process.PIPE, shell=False)
- data = cmdref.communicate()
- return (cmdref.returncode, data[0], data[1])
diff --git a/func/minion/modules/netapp/README b/func/minion/modules/netapp/README
deleted file mode 100644
index 5ecb205..0000000
--- a/func/minion/modules/netapp/README
+++ /dev/null
@@ -1,8 +0,0 @@
-This module is meant to be installed on a minion which is configured
-as an admin host for one or more NetApp filers. Since we can't get
-our funcy awesomeness on the actual filer the admin host will have to do.
-
-Requirements:
-
-- passphraseless ssh key access from root on the netapp admin minion
- to root on the target filer
diff --git a/func/minion/modules/netapp/TODO b/func/minion/modules/netapp/TODO
deleted file mode 100644
index 25d914c..0000000
--- a/func/minion/modules/netapp/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-Wrap every possible NetApp command :)
-
-I'm only going to do the ones that are important to me. If you have
-some that are important to you, feel free to submit patches to
-func-list@redhat.com and harness the power of open source!
diff --git a/func/minion/modules/netapp/__init__.py b/func/minion/modules/netapp/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/func/minion/modules/netapp/__init__.py
+++ /dev/null
diff --git a/func/minion/modules/netapp/common.py b/func/minion/modules/netapp/common.py
deleted file mode 100644
index 979c95c..0000000
--- a/func/minion/modules/netapp/common.py
+++ /dev/null
@@ -1,49 +0,0 @@
-##
-## NetApp Filer 'common' Module
-##
-## Copyright 2008, Red Hat, Inc
-## John Eckersberg <jeckersb@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import re
-import sub_process
-
-SSH = '/usr/bin/ssh'
-SSH_USER = 'root'
-SSH_OPTS = '-o forwardagent=no'
-class GenericSSHError(Exception): pass
-class NetappCommandError(Exception): pass
-
-def ssh(host, cmdargs, input=None, user=SSH_USER):
- cmdline = [SSH, SSH_OPTS, "%s@%s" % (user, host)]
- cmdline.extend(cmdargs)
-
- cmd = sub_process.Popen(cmdline,
- executable=SSH,
- stdin=sub_process.PIPE,
- stdout=sub_process.PIPE,
- stderr=sub_process.PIPE,
- shell=False)
-
- (out, err) = cmd.communicate(input)
-
- if cmd.wait() != 0:
- raise GenericSSHError, err
- else:
- return out + err
-
-def check_output(regex, output):
- #strip newlines
- output = output.replace('\n', ' ')
- if re.search(regex, output):
- return True
- else:
- raise NetappCommandError, output
-
diff --git a/func/minion/modules/netapp/snap.py b/func/minion/modules/netapp/snap.py
deleted file mode 100644
index 8f3f209..0000000
--- a/func/minion/modules/netapp/snap.py
+++ /dev/null
@@ -1,49 +0,0 @@
-##
-## NetApp Filer 'snap' Module
-##
-## Copyright 2008, Red Hat, Inc
-## John Eckersberg <jeckersb@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import re
-from func.minion.modules import func_module
-from func.minion.modules.netapp.common import *
-
-class Snap(func_module.FuncModule):
-
- # Update these if need be.
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Interface to the 'snap' command"
-
- def create(self, filer, vol, snap):
- """
- TODO: Document me ...
- """
- regex = """creating snapshot..."""
- cmd_opts = ['snap', 'create', vol, snap]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def delete(self, filer, vol, snap):
- """
- TODO: Document me ...
- """
- regex = """deleting snapshot..."""
- cmd_opts = ['snap', 'delete', vol, snap]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def list(self, filer, vol):
- """
- TODO: Document me ...
- """
- return True
-
diff --git a/func/minion/modules/netapp/vol/__init__.py b/func/minion/modules/netapp/vol/__init__.py
deleted file mode 100644
index 14ce0ac..0000000
--- a/func/minion/modules/netapp/vol/__init__.py
+++ /dev/null
@@ -1,128 +0,0 @@
-##
-## NetApp Filer 'Vol' Module
-##
-## Copyright 2008, Red Hat, Inc
-## John Eckersberg <jeckersb@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import re
-from func.minion.modules import func_module
-from func.minion.modules.netapp.common import *
-
-class Vol(func_module.FuncModule):
-
- # Update these if need be.
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Interface to the 'vol' command"
-
- def create(self, filer, vol, aggr, size):
- """
- TODO: Document me ...
- """
- regex = """Creation of volume .* has completed."""
- cmd_opts = ['vol', 'create', vol, aggr, size]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def destroy(self, filer, vol):
- """
- TODO: Document me ...
- """
- regex = """Volume .* destroyed."""
- cmd_opts = ['vol', 'destroy', vol, '-f']
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def offline(self, filer, vol):
- """
- TODO: Document me ...
- """
- regex = """Volume .* is now offline."""
- cmd_opts = ['vol', 'offline', vol]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def online(self, filer, vol):
- """
- TODO: Document me ...
- """
- regex = """Volume .* is now online."""
- cmd_opts = ['vol', 'online', vol]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def status(self, filer, vol=None):
- """
- TODO: Document me ...
- """
- cmd_opts = ['vol', 'status']
- output = ssh(filer, cmd_opts)
-
- output = output.replace(',', ' ')
- lines = output.split('\n')[1:]
-
- vols = []
- current_vol = {}
- for line in lines:
- tokens = line.split()
- if len(tokens) >= 2 and tokens[1] in ('online', 'offline', 'restricted'):
- if current_vol: vols.append(current_vol)
- current_vol = {'name': tokens[0],
- 'state': tokens[1],
- 'status': [foo for foo in tokens[2:] if '=' not in foo],
- 'options': [foo for foo in tokens[2:] if '=' in foo]}
- else:
- current_vol['status'].extend([foo for foo in tokens if '=' not in foo])
- current_vol['options'].extend([foo for foo in tokens if '=' in foo])
- vols.append(current_vol)
-
- if vol:
- try:
- return [foo for foo in vols if foo['name'] == vol][0]
- except:
- raise NetappCommandError, "No such volume: %s" % vol
- else:
- return vols
-
- def size(self, filer, vol, delta=None):
- """
- TODO: Document me ...
- """
- stat_regex = """vol size: Flexible volume .* has size .*."""
- resize_regex = """vol size: Flexible volume .* size set to .*."""
- cmd_opts = ['vol', 'size', vol]
-
- if delta:
- cmd_opts.append(delta)
- output = ssh(filer, cmd_opts)
- return check_output(resize_regex, output)
- else:
- output = ssh(filer, cmd_opts)
- check_output(stat_regex, output)
- return output.split()[-1][:-1]
-
- def options(self, filer, args):
- """
- TODO: Document me ...
- """
- pass
-
- def rename(self, filer, args):
- """
- TODO: Document me ...
- """
- pass
-
- def restrict(self, filer, args):
- """
- TODO: Document me ...
- """
- pass
diff --git a/func/minion/modules/netapp/vol/clone.py b/func/minion/modules/netapp/vol/clone.py
deleted file mode 100644
index 715d8a8..0000000
--- a/func/minion/modules/netapp/vol/clone.py
+++ /dev/null
@@ -1,46 +0,0 @@
-##
-## NetApp Filer 'vol.clone' Module
-##
-## Copyright 2008, Red Hat, Inc
-## John Eckersberg <jeckersb@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-import re
-from func.minion.modules import func_module
-from func.minion.modules.netapp.common import *
-
-class Clone(func_module.FuncModule):
-
- # Update these if need be.
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Interface to the 'vol' command"
-
- def create(self, filer, vol, parent, snap):
- """
- TODO: Document me ...
- """
- regex = """Creation of clone volume .* has completed."""
- cmd_opts = ['vol', 'clone', 'create', vol, '-b', parent, snap]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
- def split(self, filer, vol):
- """
- TODO: Document me ...
- """
- # only worry about 'start' now, I don't terribly care to automate the rest
- regex = """Clone volume .* will be split from its parent."""
- cmd_opts = ['vol', 'clone', 'split', 'start', vol]
- output = ssh(filer, cmd_opts)
- return check_output(regex, output)
-
-
-
diff --git a/func/minion/modules/networktest.py b/func/minion/modules/networktest.py
deleted file mode 100644
index 0e6fbb2..0000000
--- a/func/minion/modules/networktest.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2008, Red Hat, Inc
-# Steve 'Ashcrow' Milner <smilner@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-import func_module
-from codes import FuncException
-
-import sub_process
-
-class NetworkTest(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Defines various network testing tools."
-
- def ping(self, *args):
- if '-c' not in args:
- raise(FuncException("You must define a count with -c!"))
- return self.__run_command('/bin/ping', self.__args_to_list(args))
-
- def netstat(self, *args):
- return self.__run_command('/bin/netstat',
- self.__args_to_list(args))
-
- def traceroute(self, *args):
- return self.__run_command('/bin/traceroute',
- self.__args_to_list(args))
-
- def dig(self, *args):
- return self.__run_command('/usr/bin/dig',
- self.__args_to_list(args))
-
- def isportopen(self, host, port):
- # FIXME: the return api here needs some work... -akl
- import socket
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- timeout = 3.0
- sock.settimeout(timeout)
- try:
- sock.connect((host, int(port)))
- except socket.error, e:
- sock.close()
- return [1, ("connection to %s:%s failed" % (host, port), "%s" % e)]
- except socket.timeout:
- sock.close()
- return [2, ("connection to %s:%s timed out after %s seconds" % (host, port, timeout))]
-
- sock.close()
- return [0, "connection to %s:%s succeeded" % (host, port)]
-
- def __args_to_list(self, args):
- return [arg for arg in args]
-
- def __run_command(self, command, opts=[]):
- full_cmd = [command] + opts
- cmd = sub_process.Popen(full_cmd, stdout=sub_process.PIPE)
- return [line for line in cmd.communicate()[0].split('\n')]
diff --git a/func/minion/modules/process.py b/func/minion/modules/process.py
deleted file mode 100644
index 848e847..0000000
--- a/func/minion/modules/process.py
+++ /dev/null
@@ -1,216 +0,0 @@
-## -*- coding: utf-8 -*-
-##
-## Process lister (control TBA)
-##
-## Copyright 2007, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-# other modules
-import sub_process
-import codes
-
-# our modules
-import func_module
-
-# =================================
-
-class ProcessModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Process related reporting and control."
-
- def info(self, flags="-auxh"):
- """
- Returns a struct of hardware information. By default, this pulls down
- all of the devices. If you don't care about them, set with_devices to
- False.
- """
-
- flags.replace(";", "") # prevent stupidity
-
- cmd = sub_process.Popen(["/bin/ps", flags], executable="/bin/ps",
- stdout=sub_process.PIPE,
- stderr=sub_process.PIPE,
- shell=False)
-
- data, error = cmd.communicate()
-
- # We can get warnings for odd formatting. warnings != errors.
- if error and error[:7] != "Warning":
- raise codes.FuncException(error.split('\n')[0])
-
- results = []
- for x in data.split("\n"):
- tokens = x.split()
- results.append(tokens)
-
- return results
-
- def mem(self):
- """
- Returns a list of per-program memory usage.
-
- Private + Shared = RAM used Program
-
- [["39.4 MiB", "10.3 MiB", "49.8 MiB", "Xorg"],
- ["42.2 MiB", "12.4 MiB", "54.6 MiB", "nautilus"],
- ["52.3 MiB", "10.8 MiB", "63.0 MiB", "liferea-bin"]
- ["171.6 MiB", "11.9 MiB", "183.5 MiB", "firefox-bin"]]
-
- Taken from the ps_mem.py script written by Pádraig Brady.
- http://www.pixelbeat.org/scripts/ps_mem.py
- """
- import os
- our_pid=os.getpid()
- results = []
- have_smaps=0
- have_pss=0
-
- def kernel_ver():
- """ (major,minor,release) """
- kv=open("/proc/sys/kernel/osrelease").readline().split(".")[:3]
- for char in "-_":
- kv[2]=kv[2].split(char)[0]
- return (int(kv[0]), int(kv[1]), int(kv[2]))
-
- kv=kernel_ver()
-
- def getMemStats(pid):
- """ return Rss,Pss,Shared (note Private = Rss-Shared) """
- Shared_lines=[]
- Pss_lines=[]
- pagesize=os.sysconf("SC_PAGE_SIZE")/1024 #KiB
- Rss=int(open("/proc/"+str(pid)+"/statm").readline().split()[1])*pagesize
- if os.path.exists("/proc/"+str(pid)+"/smaps"): #stat
- global have_smaps
- have_smaps=1
- for line in open("/proc/"+str(pid)+"/smaps").readlines(): #open
- #Note in smaps Shared+Private = Rss above
- #The Rss in smaps includes video card mem etc.
- if line.startswith("Shared"):
- Shared_lines.append(line)
- elif line.startswith("Pss"):
- global have_pss
- have_pss=1
- Pss_lines.append(line)
- Shared=sum([int(line.split()[1]) for line in Shared_lines])
- Pss=sum([int(line.split()[1]) for line in Pss_lines])
- elif (2,6,1) <= kv <= (2,6,9):
- Pss=0
- Shared=0 #lots of overestimation, but what can we do?
- else:
- Pss=0
- Shared=int(open("/proc/"+str(pid)+"/statm").readline().split()[2])*pagesize
- return (Rss, Pss, Shared)
-
- cmds={}
- shareds={}
- count={}
- for pid in os.listdir("/proc/"):
- try:
- pid = int(pid) #note Thread IDs not listed in /proc/
- if pid ==our_pid: continue
- except:
- continue
- cmd = file("/proc/%d/status" % pid).readline()[6:-1]
- try:
- exe = os.path.basename(os.path.realpath("/proc/%d/exe" % pid))
- if exe.startswith(cmd):
- cmd=exe #show non truncated version
- #Note because we show the non truncated name
- #one can have separated programs as follows:
- #584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash)
- #56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin
- except:
- #permission denied or
- #kernel threads don't have exe links or
- #process gone
- continue
- try:
- rss, pss, shared = getMemStats(pid)
- private = rss-shared
- #Note shared is always a subset of rss (trs is not always)
- except:
- continue #process gone
- if shareds.get(cmd):
- if pss: #add shared portion of PSS together
- shareds[cmd]+=pss-private
- elif shareds[cmd] < shared: #just take largest shared val
- shareds[cmd]=shared
- else:
- if pss:
- shareds[cmd]=pss-private
- else:
- shareds[cmd]=shared
- cmds[cmd]=cmds.setdefault(cmd,0)+private
- if count.has_key(cmd):
- count[cmd] += 1
- else:
- count[cmd] = 1
-
- #Add max shared mem for each program
- total=0
- for cmd in cmds.keys():
- cmds[cmd]=cmds[cmd]+shareds[cmd]
- total+=cmds[cmd] #valid if PSS available
-
- sort_list = cmds.items()
- sort_list.sort(lambda x,y:cmp(x[1],y[1]))
- sort_list=filter(lambda x:x[1],sort_list) #get rid of zero sized processes
-
- #The following matches "du -h" output
- def human(num, power="Ki"):
- powers=["Ki","Mi","Gi","Ti"]
- while num >= 1000: #4 digits
- num /= 1024.0
- power=powers[powers.index(power)+1]
- return "%.1f %s" % (num,power)
-
- def cmd_with_count(cmd, count):
- if count>1:
- return "%s (%u)" % (cmd, count)
- else:
- return cmd
-
- for cmd in sort_list:
- results.append([
- "%sB" % human(cmd[1]-shareds[cmd[0]]),
- "%sB" % human(shareds[cmd[0]]),
- "%sB" % human(cmd[1]),
- "%s" % cmd_with_count(cmd[0], count[cmd[0]])
- ])
- if have_pss:
- results.append(["", "", "", "%sB" % human(total)])
-
- return results
-
- memory = mem
-
- def kill(self,pid,signal="TERM"):
- if pid == "0":
- raise codes.FuncException("Killing pid group 0 not permitted")
- if signal == "":
- # this is default /bin/kill behaviour,
- # it claims, but enfore it anyway
- signal = "-TERM"
- if signal[0] != "-":
- signal = "-%s" % signal
- rc = sub_process.call(["/bin/kill",signal, pid],
- executable="/bin/kill", shell=False)
- print rc
- return rc
-
- def pkill(self,name,level=""):
- # example killall("thunderbird","-9")
- rc = sub_process.call(["/usr/bin/pkill", name, level],
- executable="/usr/bin/pkill", shell=False)
- return rc
diff --git a/func/minion/modules/process.py.orig b/func/minion/modules/process.py.orig
deleted file mode 100644
index bdd5193..0000000
--- a/func/minion/modules/process.py.orig
+++ /dev/null
@@ -1,221 +0,0 @@
-## -*- coding: utf-8 -*-
-##
-## Process lister (control TBA)
-##
-## Copyright 2007, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-# other modules
-import sub_process
-import codes
-
-# our modules
-from modules import func_module
-
-# =================================
-
-class ProcessModule(func_module.FuncModule):
- def __init__(self):
- self.methods = {
- "info" : self.info,
- "kill" : self.kill,
- "pkill" : self.pkill,
- "mem" : self.mem
- }
- func_module.FuncModule.__init__(self)
-
- def info(self, flags="-auxh"):
- """
- Returns a struct of hardware information. By default, this pulls down
- all of the devices. If you don't care about them, set with_devices to
- False.
- """
-
- flags.replace(";", "") # prevent stupidity
-
- cmd = sub_process.Popen(["/bin/ps", flags], executable="/bin/ps",
- stdout=sub_process.PIPE,
- stderr=sub_process.PIPE,
- shell=False)
-
- data, error = cmd.communicate()
-
- # We can get warnings for odd formatting. warnings != errors.
- if error and error[:7] != "Warning":
- raise codes.FuncException(error.split('\n')[0])
-
- results = []
- for x in data.split("\n"):
- tokens = x.split()
- results.append(tokens)
-
- return results
-
- def mem(self):
- """
- Returns a list of per-program memory usage.
-
- Private + Shared = RAM used Program
-
- [["39.4 MiB", "10.3 MiB", "49.8 MiB", "Xorg"],
- ["42.2 MiB", "12.4 MiB", "54.6 MiB", "nautilus"],
- ["52.3 MiB", "10.8 MiB", "63.0 MiB", "liferea-bin"]
- ["171.6 MiB", "11.9 MiB", "183.5 MiB", "firefox-bin"]]
-
- Taken from the ps_mem.py script written by Pádraig Brady.
- http://www.pixelbeat.org/scripts/ps_mem.py
- """
- import os
- our_pid=os.getpid()
- results = []
- have_smaps=0
- have_pss=0
-
- def kernel_ver():
- """ (major,minor,release) """
- kv=open("/proc/sys/kernel/osrelease").readline().split(".")[:3]
- for char in "-_":
- kv[2]=kv[2].split(char)[0]
- return (int(kv[0]), int(kv[1]), int(kv[2]))
-
- kv=kernel_ver()
-
- def getMemStats(pid):
- """ return Rss,Pss,Shared (note Private = Rss-Shared) """
- Shared_lines=[]
- Pss_lines=[]
- pagesize=os.sysconf("SC_PAGE_SIZE")/1024 #KiB
- Rss=int(open("/proc/"+str(pid)+"/statm").readline().split()[1])*pagesize
- if os.path.exists("/proc/"+str(pid)+"/smaps"): #stat
- global have_smaps
- have_smaps=1
- for line in open("/proc/"+str(pid)+"/smaps").readlines(): #open
- #Note in smaps Shared+Private = Rss above
- #The Rss in smaps includes video card mem etc.
- if line.startswith("Shared"):
- Shared_lines.append(line)
- elif line.startswith("Pss"):
- global have_pss
- have_pss=1
- Pss_lines.append(line)
- Shared=sum([int(line.split()[1]) for line in Shared_lines])
- Pss=sum([int(line.split()[1]) for line in Pss_lines])
- elif (2,6,1) <= kv <= (2,6,9):
- Pss=0
- Shared=0 #lots of overestimation, but what can we do?
- else:
- Pss=0
- Shared=int(open("/proc/"+str(pid)+"/statm").readline().split()[2])*pagesize
- return (Rss, Pss, Shared)
-
- cmds={}
- shareds={}
- count={}
- for pid in os.listdir("/proc/"):
- try:
- pid = int(pid) #note Thread IDs not listed in /proc/
- if pid ==our_pid: continue
- except:
- continue
- cmd = file("/proc/%d/status" % pid).readline()[6:-1]
- try:
- exe = os.path.basename(os.path.realpath("/proc/%d/exe" % pid))
- if exe.startswith(cmd):
- cmd=exe #show non truncated version
- #Note because we show the non truncated name
- #one can have separated programs as follows:
- #584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash)
- #56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin
- except:
- #permission denied or
- #kernel threads don't have exe links or
- #process gone
- continue
- try:
- rss, pss, shared = getMemStats(pid)
- private = rss-shared
- #Note shared is always a subset of rss (trs is not always)
- except:
- continue #process gone
- if shareds.get(cmd):
- if pss: #add shared portion of PSS together
- shareds[cmd]+=pss-private
- elif shareds[cmd] < shared: #just take largest shared val
- shareds[cmd]=shared
- else:
- if pss:
- shareds[cmd]=pss-private
- else:
- shareds[cmd]=shared
- cmds[cmd]=cmds.setdefault(cmd,0)+private
- if count.has_key(cmd):
- count[cmd] += 1
- else:
- count[cmd] = 1
-
- #Add max shared mem for each program
- total=0
- for cmd in cmds.keys():
- cmds[cmd]=cmds[cmd]+shareds[cmd]
- total+=cmds[cmd] #valid if PSS available
-
- sort_list = cmds.items()
- sort_list.sort(lambda x,y:cmp(x[1],y[1]))
- sort_list=filter(lambda x:x[1],sort_list) #get rid of zero sized processes
-
- #The following matches "du -h" output
- def human(num, power="Ki"):
- powers=["Ki","Mi","Gi","Ti"]
- while num >= 1000: #4 digits
- num /= 1024.0
- power=powers[powers.index(power)+1]
- return "%.1f %s" % (num,power)
-
- def cmd_with_count(cmd, count):
- if count>1:
- return "%s (%u)" % (cmd, count)
- else:
- return cmd
-
- for cmd in sort_list:
- results.append([
- "%sB" % human(cmd[1]-shareds[cmd[0]]),
- "%sB" % human(shareds[cmd[0]]),
- "%sB" % human(cmd[1]),
- "%s" % cmd_with_count(cmd[0], count[cmd[0]])
- ])
- if have_pss:
- results.append(["", "", "", "%sB" % human(total)])
-
- return results
-
- def kill(self,pid,signal="TERM"):
- if pid == "0":
- raise codes.FuncException("Killing pid group 0 not permitted")
- if signal == "":
- # this is default /bin/kill behaviour,
- # it claims, but enfore it anyway
- signal = "-TERM"
- if signal[0] != "-":
- signal = "-%s" % signal
- rc = sub_process.call(["/bin/kill",signal, pid],
- executable="/bin/kill", shell=False)
- print rc
- return rc
-
- def pkill(self,name,level=""):
- # example killall("thunderbird","-9")
- rc = sub_process.call(["/usr/bin/pkill", name, level],
- executable="/usr/bin/pkill", shell=False)
- return rc
-
-methods = ProcessModule()
-register_rpc = methods.register_rpc
diff --git a/func/minion/modules/reboot.py b/func/minion/modules/reboot.py
deleted file mode 100644
index c4fb275..0000000
--- a/func/minion/modules/reboot.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# James Bowes <jbowes@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import func_module
-import sub_process
-
-class Reboot(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Reboots a machine."
-
- def reboot(self, when='now', message=''):
- return sub_process.call(["/sbin/shutdown", '-r', when, message])
diff --git a/func/minion/modules/rpms.py b/func/minion/modules/rpms.py
deleted file mode 100644
index ae26cb4..0000000
--- a/func/minion/modules/rpms.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# Michael DeHaan <mdehaan@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import func_module
-import rpm
-
-class RpmModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "RPM related commands."
-
- def inventory(self, flatten=True):
- """
- Returns information on all installed packages.
- By default, 'flatten' is passed in as True, which makes printouts very
- clean in diffs for use by func-inventory. If you are writting another
- software application, using flatten=False will prevent the need to
- parse the returns.
- """
- # I have not been able to get flatten=False to work if there
- # is more than 491 entries in the dict -- ashcrow
- ts = rpm.TransactionSet()
- mi = ts.dbMatch()
- results = []
- for hdr in mi:
- name = hdr['name']
- epoch = (hdr['epoch'] or 0)
- version = hdr['version']
- release = hdr['release']
- arch = hdr['arch']
- if flatten:
- results.append("%s %s %s %s %s" % (name, epoch, version,
- release, arch))
- else:
- results.append([name, epoch, version, release, arch])
- return results
diff --git a/func/minion/modules/service.py b/func/minion/modules/service.py
deleted file mode 100644
index 062aea5..0000000
--- a/func/minion/modules/service.py
+++ /dev/null
@@ -1,88 +0,0 @@
-## func
-##
-## Copyright 2007, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-##
-
-import codes
-import func_module
-
-import sub_process
-import os
-
-class Service(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Allows for service control via func."
-
- def __command(self, service_name, command):
-
- filename = os.path.join("/etc/rc.d/init.d/",service_name)
- if os.path.exists(filename):
- return sub_process.call(["/sbin/service", service_name, command])
- else:
- raise codes.FuncException("Service not installed: %s" % service_name)
-
- def start(self, service_name):
- return self.__command(service_name, "start")
-
- def stop(self, service_name):
- return self.__command(service_name, "stop")
-
- def restart(self, service_name):
- return self.__command(service_name, "restart")
-
- def reload(self, service_name):
- return self.__command(service_name, "reload")
-
- def status(self, service_name):
- return self.__command(service_name, "status")
-
- def inventory(self):
- return {
- "running" : self.get_running(),
- "enabled" : self.get_enabled()
- }
-
- def get_enabled(self):
- """
- Get the list of services that are enabled at the various runlevels. Xinetd services
- only provide whether or not they are running, not specific runlevel info.
- """
-
- chkconfig = sub_process.Popen(["/sbin/chkconfig", "--list"], stdout=sub_process.PIPE)
- data = chkconfig.communicate()[0]
- results = []
- for line in data.split("\n"):
- if line.find("0:") != -1:
- # regular services
- tokens = line.split()
- results.append((tokens[0],tokens[1:]))
- elif line.find(":") != -1 and not line.endswith(":"):
- # xinetd.d based services
- tokens = line.split()
- tokens[0] = tokens[0].replace(":","")
- results.append((tokens[0],tokens[1]))
- return results
-
- def get_running(self):
- """
- Get a list of which services are running, stopped, or disabled.
- """
- chkconfig = sub_process.Popen(["/sbin/service", "--status-all"], stdout=sub_process.PIPE)
- data = chkconfig.communicate()[0]
- results = []
- for line in data.split("\n"):
- if line.find(" is ") != -1:
- tokens = line.split()
- results.append((tokens[0], tokens[-1].replace("...","")))
- return results
diff --git a/func/minion/modules/smart.py b/func/minion/modules/smart.py
deleted file mode 100644
index f410f09..0000000
--- a/func/minion/modules/smart.py
+++ /dev/null
@@ -1,47 +0,0 @@
-##
-## Grabs status from SMART to see if your hard drives are ok
-## Returns in the format of (return code, [line1, line2, line3,...])
-##
-## Copyright 2007, Red Hat, Inc
-## Michael DeHaan <mdehaan@redhat.com>
-##
-## This software may be freely redistributed under the terms of the GNU
-## general public license.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-##
-
-# other modules
-import sub_process
-
-# our modules
-import func_module
-
-# =================================
-
-class SmartModule(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Grabs status from SMART to see if your hard drives are ok."
-
- def info(self,flags="-q onecheck"):
- """
- Returns a struct of hardware information. By default, this pulls down
- all of the devices. If you don't care about them, set with_devices to
- False.
- """
-
- flags.replace(";","") # prevent stupidity
-
- cmd = sub_process.Popen("/usr/sbin/smartd %s" % flags,stdout=sub_process.PIPE,shell=True)
- data = cmd.communicate()[0]
-
- results = []
-
- for x in data.split("\n"):
- results.append(x)
-
- return (cmd.returncode, results)
diff --git a/func/minion/modules/snmp.py b/func/minion/modules/snmp.py
deleted file mode 100644
index c992db1..0000000
--- a/func/minion/modules/snmp.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# James Bowes <jbowes@redhat.com>
-# Seth Vidal modified command.py to be snmp.py
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-"""
-Abitrary command execution module for func.
-"""
-
-import func_module
-import sub_process
-base_snmp_command = '/usr/bin/snmpget -v2c -Ov -OQ'
-
-class Snmp(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "SNMP related calls through func."
-
- def get(self, oid, rocommunity, hostname='localhost'):
- """
- Runs an snmpget on a specific oid returns the output of the call.
- """
- command = '%s -c %s %s %s' % (base_snmp_command, rocommunity, hostname, oid)
-
- cmdref = sub_process.Popen(command.split(),stdout=sub_process.PIPE,stderr=sub_process.PIPE, shell=False)
- data = cmdref.communicate()
- return (cmdref.returncode, data[0], data[1])
-
- #def walk(self, oid, rocommunity):
-
- #def table(self, oid, rocommunity):
diff --git a/func/minion/modules/sysctl.py b/func/minion/modules/sysctl.py
deleted file mode 100644
index 1f11d55..0000000
--- a/func/minion/modules/sysctl.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2008, Red Hat, Inc
-# Luke Macken <lmacken@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import func_module
-import sub_process
-
-class SysctlModule(func_module.FuncModule):
-
- version = "0.0.1"
- description = "Configure kernel parameters at runtime"
-
- def __run(self, cmd):
- cmd = sub_process.Popen(cmd.split(), stdout=sub_process.PIPE,
- stderr=sub_process.PIPE, shell=False)
- return [line for line in cmd.communicate()[0].strip().split('\n')]
-
- def list(self):
- return self.__run("/sbin/sysctl -a")
-
- def get(self, name):
- return self.__run("/sbin/sysctl -n %s" % name)
-
- def set(self, name, value):
- return self.__run("/sbin/sysctl -w %s=%s" % (name, value))
diff --git a/func/minion/modules/test.py b/func/minion/modules/test.py
deleted file mode 100644
index 6f7c5fa..0000000
--- a/func/minion/modules/test.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import func_module
-import time
-import exceptions
-
-class Test(func_module.FuncModule):
- version = "11.11.11"
- api_version = "0.0.1"
- description = "Just a very simple example module"
-
- def add(self, numb1, numb2):
- return numb1 + numb2
-
- def ping(self):
- return 1
-
- def sleep(self,t):
- """
- Sleeps for t seconds, and returns time of day.
- Simply a test function for trying out async and threaded voodoo.
- """
- t = int(t)
- time.sleep(t)
- return time.time()
-
- def explode(self):
- """
- Testing remote exception handling is useful
- """
- raise exceptions.Exception("khhhhhhaaaaaan!!!!!!")
diff --git a/func/minion/modules/virt.py b/func/minion/modules/virt.py
deleted file mode 100644
index 04d36bd..0000000
--- a/func/minion/modules/virt.py
+++ /dev/null
@@ -1,277 +0,0 @@
-"""
-Virt management features
-
-Copyright 2007, Red Hat, Inc
-Michael DeHaan <mdehaan@redhat.com>
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-# warning: virt management is rather complicated
-# to see a simple example of func, look at the
-# service control module. API docs on how
-# to use this to come.
-
-# other modules
-import os
-import sub_process
-import libvirt
-
-# our modules
-import codes
-import func_module
-
-VIRT_STATE_NAME_MAP = {
- 0 : "running",
- 1 : "running",
- 2 : "running",
- 3 : "paused",
- 4 : "shutdown",
- 5 : "shutdown",
- 6 : "crashed"
-}
-
-class FuncLibvirtConnection(object):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Virtualization items through func."
-
- def __init__(self):
-
- cmd = sub_process.Popen("uname -r", shell=True, stdout=sub_process.PIPE)
- output = cmd.communicate()[0]
-
- if output.find("xen") != -1:
- conn = libvirt.open(None)
- else:
- conn = libvirt.open("qemu:///system")
-
- if not conn:
- raise codes.FuncException("hypervisor connection failure")
-
- self.conn = conn
-
- def find_vm(self, vmid):
- """
- Extra bonus feature: vmid = -1 returns a list of everything
- """
- conn = self.conn
-
- vms = []
-
- # this block of code borrowed from virt-manager:
- # get working domain's name
- ids = conn.listDomainsID();
- for id in ids:
- vm = conn.lookupByID(id)
- vms.append(vm)
- # get defined domain
- names = conn.listDefinedDomains()
- for name in names:
- vm = conn.lookupByName(name)
- vms.append(vm)
-
- if vmid == -1:
- return vms
-
- for vm in vms:
- if vm.name() == vmid:
- return vm
-
- raise codes.FuncException("virtual machine %s not found" % vmid)
-
- def shutdown(self, vmid):
- return self.find_vm(vmid).shutdown()
-
- def pause(self, vmid):
- return self.suspend(self.conn,vmid)
-
- def unpause(self, vmid):
- return self.resume(self.conn,vmid)
-
- def suspend(self, vmid):
- return self.find_vm(vmid).suspend()
-
- def resume(self, vmid):
- return self.find_vm(vmid).resume()
-
- def create(self, vmid):
- return self.find_vm(vmid).create()
-
- def destroy(self, vmid):
- return self.find_vm(vmid).destroy()
-
- def undefine(self, vmid):
- return self.find_vm(vmid).undefine()
-
- def get_status2(self, vm):
- state = vm.info()[0]
- # print "DEBUG: state: %s" % state
- return VIRT_STATE_NAME_MAP.get(state,"unknown")
-
- def get_status(self, vmid):
- state = self.find_vm(vmid).info()[0]
- return VIRT_STATE_NAME_MAP.get(state,"unknown")
-
-
-
-class Virt(func_module.FuncModule):
-
- def __get_conn(self):
- self.conn = FuncLibvirtConnection()
- return self.conn
-
- def state(self):
- vms = self.list_vms()
- state = []
- for vm in vms:
- state_blurb = self.conn.get_status(vm)
- state.append("%s %s" % (vm,state_blurb))
- return state
-
-
- def info(self):
- vms = self.list_vms()
- info = dict()
- for vm in vms:
- data = self.conn.find_vm(vm).info()
- # libvirt returns maxMem, memory, and cpuTime as long()'s, which
- # xmlrpclib tries to convert to regular int's during serialization.
- # This throws exceptions, so convert them to strings here and
- # assume the other end of the xmlrpc connection can figure things
- # out or doesn't care.
- info[vm] = {
- "state" : VIRT_STATE_NAME_MAP.get(data[0],"unknown"),
- "maxMem" : str(data[1]),
- "memory" : str(data[2]),
- "nrVirtCpu" : data[3],
- "cpuTime" : str(data[4])
- }
- return info
-
-
- def list_vms(self):
- self.conn = self.__get_conn()
- vms = self.conn.find_vm(-1)
- results = []
- for x in vms:
- try:
- results.append(x.name())
- except:
- pass
- return results
-
- def install(self, server_name, target_name, system=False):
-
- """
- Install a new virt system by way of a named cobbler profile.
- """
-
- # Example:
- # install("bootserver.example.org", "fc7webserver", True)
-
- conn = self.__get_conn()
-
- if conn is None:
- raise codes.FuncException("no connection")
-
- if not os.path.exists("/usr/bin/koan"):
- raise codes.FuncException("no /usr/bin/koan")
- target = "profile"
- if system:
- target = "system"
-
- # TODO: FUTURE: set --virt-path in cobbler or here
- koan_args = [
- "/usr/bin/koan",
- "--virt",
- "--virt-graphics", # enable VNC
- "--%s=%s" % (target, target_name),
- "--server=%s" % server_name
- ]
-
- rc = sub_process.call(koan_args,shell=False)
- if rc == 0:
- return 0
- else:
- raise codes.FuncException("koan returned %d" % rc)
-
-
- def shutdown(self, vmid):
- """
- Make the machine with the given vmid stop running.
- Whatever that takes.
- """
- self.__get_conn()
- self.conn.shutdown(vmid)
- return 0
-
-
- def pause(self, vmid):
-
- """
- Pause the machine with the given vmid.
- """
- self.__get_conn()
- self.conn.suspend(vmid)
- return 0
-
-
- def unpause(self, vmid):
-
- """
- Unpause the machine with the given vmid.
- """
-
- self.__get_conn()
- self.conn.resume(vmid)
- return 0
-
-
- def create(self, vmid):
-
- """
- Start the machine via the given mac address.
- """
- self.__get_conn()
- self.conn.create(vmid)
- return 0
-
-
- def destroy(self, vmid):
-
- """
- Pull the virtual power from the virtual domain, giving it virtually no
- time to virtually shut down.
- """
- self.__get_conn()
- self.conn.destroy(vmid)
- return 0
-
-
- def undefine(self, vmid):
-
- """
- Stop a domain, and then wipe it from the face of the earth.
- by deleting the disk image and it's configuration file.
- """
-
- self.__get_conn()
- self.conn.undefine(vmid)
- return 0
-
-
- def get_status(self, vmid):
-
- """
- Return a state suitable for server consumption. Aka, codes.py values, not XM output.
- """
-
- self.__get_conn()
- return self.conn.get_status(vmid)
diff --git a/func/minion/modules/yumcmd.py b/func/minion/modules/yumcmd.py
deleted file mode 100644
index f952372..0000000
--- a/func/minion/modules/yumcmd.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2007, Red Hat, Inc
-# James Bowes <jbowes@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import func_module
-
-import yum
-
-# XXX Use internal yum callback or write a useful one.
-class DummyCallback(object):
-
- def event(self, state, data=None):
- pass
-
-class Yum(func_module.FuncModule):
-
- version = "0.0.1"
- api_version = "0.0.1"
- description = "Package updates through yum."
-
- def update(self):
- # XXX support updating specific rpms
- ayum = yum.YumBase()
- ayum.doGenericSetup()
- ayum.doRepoSetup()
- try:
- ayum.doLock()
- ayum.update()
- ayum.buildTransaction()
- ayum.processTransaction(
- callback=DummyCallback())
- finally:
- ayum.closeRpmDB()
- ayum.doUnlock()
- return True
-
- def check_update(self, repo=None):
- """Returns a list of packages due to be updated"""
- ayum = yum.YumBase()
- ayum.doConfigSetup()
- ayum.doTsSetup()
- if repo is not None:
- ayum.repos.enableRepo(repo)
- return map(str, ayum.doPackageLists('updates').updates)
diff --git a/func/minion/server.py b/func/minion/server.py
deleted file mode 100755
index f1b827f..0000000
--- a/func/minion/server.py
+++ /dev/null
@@ -1,285 +0,0 @@
-"""
-func
-
-Copyright 2007, Red Hat, Inc
-see AUTHORS
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-# standard modules
-import SimpleXMLRPCServer
-import string
-import sys
-import traceback
-import socket
-import fnmatch
-
-from gettext import textdomain
-I18N_DOMAIN = "func"
-
-
-from func.config import read_config
-from func.commonconfig import FuncdConfig
-from func import logger
-from func import certs
-import func.jobthing as jobthing
-import utils
-
-# our modules
-import AuthedXMLRPCServer
-import codes
-import module_loader
-import func.utils as futils
-
-
-
-class XmlRpcInterface(object):
-
- def __init__(self):
-
- """
- Constructor.
- """
-
- config_file = '/etc/func/minion.conf'
- self.config = read_config(config_file, FuncdConfig)
- self.logger = logger.Logger().logger
- self.audit_logger = logger.AuditLogger()
- self.__setup_handlers()
-
- # need a reference so we can log ip's, certs, etc
- # self.server = server
-
- def __setup_handlers(self):
-
- """
- Add RPC functions from each class to the global list so they can be called.
- """
-
- self.handlers = {}
- for x in self.modules.keys():
- try:
- self.modules[x].register_rpc(self.handlers, x)
- self.logger.debug("adding %s" % x)
- except AttributeError, e:
- self.logger.warning("module %s not loaded, missing register_rpc method" % self.modules[x])
-
-
- # internal methods that we do instead of spreading internal goo
- # all over the modules. For now, at lest -akl
-
-
- # system.listMethods os a quasi stanard xmlrpc method, so
- # thats why it has a odd looking name
- self.handlers["system.listMethods"] = self.list_methods
- self.handlers["system.list_methods"] = self.list_methods
- self.handlers["system.list_modules"] = self.list_modules
-
- def list_modules(self):
- modules = self.modules.keys()
- modules.sort()
- return modules
-
- def list_methods(self):
- methods = self.handlers.keys()
- methods.sort()
- return methods
-
- def get_dispatch_method(self, method):
-
- if method in self.handlers:
- return FuncApiMethod(self.logger, method, self.handlers[method])
-
- else:
- self.logger.info("Unhandled method call for method: %s " % method)
- raise codes.InvalidMethodException
-
-
-class FuncApiMethod:
-
- """
- Used to hold a reference to all of the registered functions.
- """
-
- def __init__(self, logger, name, method):
-
- self.logger = logger
- self.__method = method
- self.__name = name
-
- def __log_exc(self):
-
- """
- Log an exception.
- """
-
- (t, v, tb) = sys.exc_info()
- self.logger.info("Exception occured: %s" % t )
- self.logger.info("Exception value: %s" % v)
- self.logger.info("Exception Info:\n%s" % string.join(traceback.format_list(traceback.extract_tb(tb))))
-
- def __call__(self, *args):
-
- self.logger.debug("(X) -------------------------------------------")
-
- try:
- rc = self.__method(*args)
- except codes.FuncException, e:
- self.__log_exc()
- (t, v, tb) = sys.exc_info()
- rc = futils.nice_exception(t,v,tb)
- except:
- self.__log_exc()
- (t, v, tb) = sys.exc_info()
- rc = futils.nice_exception(t,v,tb)
- self.logger.debug("Return code for %s: %s" % (self.__name, rc))
-
- return rc
-
-
-def serve():
-
- """
- Code for starting the XMLRPC service.
- """
- server =FuncSSLXMLRPCServer(('', 51234))
- server.logRequests = 0 # don't print stuff to console
- server.serve_forever()
-
-
-
-class FuncXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, XmlRpcInterface):
-
- def __init__(self, args):
-
- self.allow_reuse_address = True
-
- self.modules = module_loader.load_modules()
- SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, args)
- XmlRpcInterface.__init__(self)
-
-
-class FuncSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer,
- XmlRpcInterface):
- def __init__(self, args):
- self.allow_reuse_address = True
- self.modules = module_loader.load_modules()
-
- XmlRpcInterface.__init__(self)
- hn = utils.get_hostname()
- self.key = "%s/%s.pem" % (self.config.cert_dir, hn)
- self.cert = "%s/%s.cert" % (self.config.cert_dir, hn)
- self.ca = "%s/ca.cert" % self.config.cert_dir
-
- self._our_ca = certs.retrieve_cert_from_file(self.ca)
-
- AuthedXMLRPCServer.AuthedSSLXMLRPCServer.__init__(self, ("", 51234),
- self.key, self.cert,
- self.ca)
-
- def _dispatch(self, method, params):
-
- """
- the SimpleXMLRPCServer class will call _dispatch if it doesn't
- find a handler method
- """
- # take _this_request and hand it off to check out the acls of the method
- # being called vs the requesting host
-
- if not hasattr(self, '_this_request'):
- raise codes.InvalidMethodException
-
- r,a = self._this_request
- peer_cert = r.get_peer_certificate()
- ip = a[0]
-
-
- # generally calling conventions are: hardware.info
- # async convention is async.hardware.info
- # here we parse out the async to decide how to invoke it.
- # see the async docs on the Wiki for further info.
- async_dispatch = False
- if method.startswith("async."):
- async_dispatch = True
- method = method.replace("async.","",1)
-
- if not self._check_acl(peer_cert, ip, method, params):
- raise codes.AccessToMethodDenied
-
- # Recognize ipython's tab completion calls
- if method == 'trait_names' or method == '_getAttributeNames':
- return self.handlers.keys()
-
- cn = peer_cert.get_subject().CN
- sub_hash = peer_cert.subject_name_hash()
- self.audit_logger.log_call(ip, cn, sub_hash, method, params)
-
- try:
- if not async_dispatch:
- return self.get_dispatch_method(method)(*params)
- else:
- return jobthing.minion_async_run(self.get_dispatch_method, method, params)
- except:
- (t, v, tb) = sys.exc_info()
- rc = futils.nice_exception(t, v, tb)
- return rc
-
- def auth_cb(self, request, client_address):
- peer_cert = request.get_peer_certificate()
- return peer_cert.get_subject().CN
-
- def _check_acl(self, cert, ip, method, params):
- acls = utils.get_acls_from_config(acldir=self.config.acl_dir)
-
- # certmaster always gets to run things
- ca_cn = self._our_ca.get_subject().CN
- ca_hash = self._our_ca.subject_name_hash()
- ca_key = '%s-%s' % (ca_cn, ca_hash)
- acls[ca_key] = ['*']
-
- cn = cert.get_subject().CN
- sub_hash = cert.subject_name_hash()
- if acls:
- allow_list = []
- hostkey = '%s-%s' % (cn, sub_hash)
- # search all the keys, match to 'cn-subhash'
- for hostmatch in acls.keys():
- if fnmatch.fnmatch(hostkey, hostmatch):
- allow_list.extend(acls[hostmatch])
- # go through the allow_list and make sure this method is in there
- for methodmatch in allow_list:
- if fnmatch.fnmatch(method, methodmatch):
- return True
-
- return False
-
-
-def main(argv):
-
- """
- Start things up.
- """
-
- if "daemon" in sys.argv or "--daemon" in sys.argv:
- futils.daemonize("/var/run/funcd.pid")
- else:
- print "serving...\n"
-
- try:
- utils.create_minion_keys()
- serve()
- except codes.FuncException, e:
- print >> sys.stderr, 'error: %s' % e
- sys.exit(1)
-
-
-# ======================================================================================
-if __name__ == "__main__":
- textdomain(I18N_DOMAIN)
- main(sys.argv)
diff --git a/func/minion/sub_process.py b/func/minion/sub_process.py
deleted file mode 100644
index 351a951..0000000
--- a/func/minion/sub_process.py
+++ /dev/null
@@ -1,1221 +0,0 @@
-# subprocess - Subprocesses with accessible I/O streams
-#
-# For more information about this module, see PEP 324.
-#
-# This module should remain compatible with Python 2.2, see PEP 291.
-#
-# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
-#
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/2.4/license for licensing details.
-
-r"""subprocess - Subprocesses with accessible I/O streams
-
-This module allows you to spawn processes, connect to their
-input/output/error pipes, and obtain their return codes. This module
-intends to replace several other, older modules and functions, like:
-
-os.system
-os.spawn*
-os.popen*
-popen2.*
-commands.*
-
-Information about how the subprocess module can be used to replace these
-modules and functions can be found below.
-
-
-
-Using the subprocess module
-===========================
-This module defines one class called Popen:
-
-class Popen(args, bufsize=0, executable=None,
- stdin=None, stdout=None, stderr=None,
- preexec_fn=None, close_fds=False, shell=False,
- cwd=None, env=None, universal_newlines=False,
- startupinfo=None, creationflags=0):
-
-
-Arguments are:
-
-args should be a string, or a sequence of program arguments. The
-program to execute is normally the first item in the args sequence or
-string, but can be explicitly set by using the executable argument.
-
-On UNIX, with shell=False (default): In this case, the Popen class
-uses os.execvp() to execute the child program. args should normally
-be a sequence. A string will be treated as a sequence with the string
-as the only item (the program to execute).
-
-On UNIX, with shell=True: If args is a string, it specifies the
-command string to execute through the shell. If args is a sequence,
-the first item specifies the command string, and any additional items
-will be treated as additional shell arguments.
-
-On Windows: the Popen class uses CreateProcess() to execute the child
-program, which operates on strings. If args is a sequence, it will be
-converted to a string using the list2cmdline method. Please note that
-not all MS Windows applications interpret the command line the same
-way: The list2cmdline is designed for applications using the same
-rules as the MS C runtime.
-
-bufsize, if given, has the same meaning as the corresponding argument
-to the built-in open() function: 0 means unbuffered, 1 means line
-buffered, any other positive value means use a buffer of
-(approximately) that size. A negative bufsize means to use the system
-default, which usually means fully buffered. The default value for
-bufsize is 0 (unbuffered).
-
-stdin, stdout and stderr specify the executed programs' standard
-input, standard output and standard error file handles, respectively.
-Valid values are PIPE, an existing file descriptor (a positive
-integer), an existing file object, and None. PIPE indicates that a
-new pipe to the child should be created. With None, no redirection
-will occur; the child's file handles will be inherited from the
-parent. Additionally, stderr can be STDOUT, which indicates that the
-stderr data from the applications should be captured into the same
-file handle as for stdout.
-
-If preexec_fn is set to a callable object, this object will be called
-in the child process just before the child is executed.
-
-If close_fds is true, all file descriptors except 0, 1 and 2 will be
-closed before the child process is executed.
-
-if shell is true, the specified command will be executed through the
-shell.
-
-If cwd is not None, the current directory will be changed to cwd
-before the child is executed.
-
-If env is not None, it defines the environment variables for the new
-process.
-
-If universal_newlines is true, the file objects stdout and stderr are
-opened as a text files, but lines may be terminated by any of '\n',
-the Unix end-of-line convention, '\r', the Macintosh convention or
-'\r\n', the Windows convention. All of these external representations
-are seen as '\n' by the Python program. Note: This feature is only
-available if Python is built with universal newline support (the
-default). Also, the newlines attribute of the file objects stdout,
-stdin and stderr are not updated by the communicate() method.
-
-The startupinfo and creationflags, if given, will be passed to the
-underlying CreateProcess() function. They can specify things such as
-appearance of the main window and priority for the new process.
-(Windows only)
-
-
-This module also defines two shortcut functions:
-
-call(*popenargs, **kwargs):
- Run command with arguments. Wait for command to complete, then
- return the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- retcode = call(["ls", "-l"])
-
-check_call(*popenargs, **kwargs):
- Run command with arguments. Wait for command to complete. If the
- exit code was zero then return, otherwise raise
- CalledProcessError. The CalledProcessError object will have the
- return code in the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- check_call(["ls", "-l"])
-
-Exceptions
-----------
-Exceptions raised in the child process, before the new program has
-started to execute, will be re-raised in the parent. Additionally,
-the exception object will have one extra attribute called
-'child_traceback', which is a string containing traceback information
-from the childs point of view.
-
-The most common exception raised is OSError. This occurs, for
-example, when trying to execute a non-existent file. Applications
-should prepare for OSErrors.
-
-A ValueError will be raised if Popen is called with invalid arguments.
-
-check_call() will raise CalledProcessError, if the called process
-returns a non-zero return code.
-
-
-Security
---------
-Unlike some other popen functions, this implementation will never call
-/bin/sh implicitly. This means that all characters, including shell
-metacharacters, can safely be passed to child processes.
-
-
-Popen objects
-=============
-Instances of the Popen class have the following methods:
-
-poll()
- Check if child process has terminated. Returns returncode
- attribute.
-
-wait()
- Wait for child process to terminate. Returns returncode attribute.
-
-communicate(input=None)
- Interact with process: Send data to stdin. Read data from stdout
- and stderr, until end-of-file is reached. Wait for process to
- terminate. The optional stdin argument should be a string to be
- sent to the child process, or None, if no data should be sent to
- the child.
-
- communicate() returns a tuple (stdout, stderr).
-
- Note: The data read is buffered in memory, so do not use this
- method if the data size is large or unlimited.
-
-The following attributes are also available:
-
-stdin
- If the stdin argument is PIPE, this attribute is a file object
- that provides input to the child process. Otherwise, it is None.
-
-stdout
- If the stdout argument is PIPE, this attribute is a file object
- that provides output from the child process. Otherwise, it is
- None.
-
-stderr
- If the stderr argument is PIPE, this attribute is file object that
- provides error output from the child process. Otherwise, it is
- None.
-
-pid
- The process ID of the child process.
-
-returncode
- The child return code. A None value indicates that the process
- hasn't terminated yet. A negative value -N indicates that the
- child was terminated by signal N (UNIX only).
-
-
-Replacing older functions with the subprocess module
-====================================================
-In this section, "a ==> b" means that b can be used as a replacement
-for a.
-
-Note: All functions in this section fail (more or less) silently if
-the executed program cannot be found; this module raises an OSError
-exception.
-
-In the following examples, we assume that the subprocess module is
-imported with "from subprocess import *".
-
-
-Replacing /bin/sh shell backquote
----------------------------------
-output=`mycmd myarg`
-==>
-output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
-
-
-Replacing shell pipe line
--------------------------
-output=`dmesg | grep hda`
-==>
-p1 = Popen(["dmesg"], stdout=PIPE)
-p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
-output = p2.communicate()[0]
-
-
-Replacing os.system()
----------------------
-sts = os.system("mycmd" + " myarg")
-==>
-p = Popen("mycmd" + " myarg", shell=True)
-pid, sts = os.waitpid(p.pid, 0)
-
-Note:
-
-* Calling the program through the shell is usually not required.
-
-* It's easier to look at the returncode attribute than the
- exitstatus.
-
-A more real-world example would look like this:
-
-try:
- retcode = call("mycmd" + " myarg", shell=True)
- if retcode < 0:
- print >>sys.stderr, "Child was terminated by signal", -retcode
- else:
- print >>sys.stderr, "Child returned", retcode
-except OSError, e:
- print >>sys.stderr, "Execution failed:", e
-
-
-Replacing os.spawn*
--------------------
-P_NOWAIT example:
-
-pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
-==>
-pid = Popen(["/bin/mycmd", "myarg"]).pid
-
-
-P_WAIT example:
-
-retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
-==>
-retcode = call(["/bin/mycmd", "myarg"])
-
-
-Vector example:
-
-os.spawnvp(os.P_NOWAIT, path, args)
-==>
-Popen([path] + args[1:])
-
-
-Environment example:
-
-os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
-==>
-Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
-
-
-Replacing os.popen*
--------------------
-pipe = os.popen(cmd, mode='r', bufsize)
-==>
-pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
-
-pipe = os.popen(cmd, mode='w', bufsize)
-==>
-pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
-
-
-(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
- stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdin, child_stdout) = (p.stdin, p.stdout)
-
-
-(child_stdin,
- child_stdout,
- child_stderr) = os.popen3(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
- stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
-(child_stdin,
- child_stdout,
- child_stderr) = (p.stdin, p.stdout, p.stderr)
-
-
-(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
- stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
-(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
-
-
-Replacing popen2.*
-------------------
-Note: If the cmd argument to popen2 functions is a string, the command
-is executed through /bin/sh. If it is a list, the command is directly
-executed.
-
-(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
-==>
-p = Popen(["somestring"], shell=True, bufsize=bufsize
- stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdout, child_stdin) = (p.stdout, p.stdin)
-
-
-(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
-==>
-p = Popen(["mycmd", "myarg"], bufsize=bufsize,
- stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdout, child_stdin) = (p.stdout, p.stdin)
-
-The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
-except that:
-
-* subprocess.Popen raises an exception if the execution fails
-* the capturestderr argument is replaced with the stderr argument.
-* stdin=PIPE and stdout=PIPE must be specified.
-* popen2 closes all filedescriptors by default, but you have to specify
- close_fds=True with subprocess.Popen.
-
-
-"""
-
-import sys
-mswindows = (sys.platform == "win32")
-
-import os
-import types
-import traceback
-
-# Exception classes used by this module.
-class CalledProcessError(Exception):
- """This exception is raised when a process run by check_call() returns
- a non-zero exit status. The exit status will be stored in the
- returncode attribute."""
- def __init__(self, returncode, cmd):
- self.returncode = returncode
- self.cmd = cmd
- def __str__(self):
- return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
-
-
-if mswindows:
- import threading
- import msvcrt
- if 0: # <-- change this to use pywin32 instead of the _subprocess driver
- import pywintypes
- from win32api import GetStdHandle, STD_INPUT_HANDLE, \
- STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
- from win32api import GetCurrentProcess, DuplicateHandle, \
- GetModuleFileName, GetVersion
- from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE
- from win32pipe import CreatePipe
- from win32process import CreateProcess, STARTUPINFO, \
- GetExitCodeProcess, STARTF_USESTDHANDLES, \
- STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
- from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
- else:
- from _subprocess import *
- class STARTUPINFO:
- dwFlags = 0
- hStdInput = None
- hStdOutput = None
- hStdError = None
- wShowWindow = 0
- class pywintypes:
- error = IOError
-else:
- import select
- import errno
- import fcntl
- import pickle
-
-__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"]
-
-try:
- MAXFD = os.sysconf("SC_OPEN_MAX")
-except:
- MAXFD = 256
-
-# True/False does not exist on 2.2.0
-try:
- False
-except NameError:
- False = 0
- True = 1
-
-_active = []
-
-def _cleanup():
- for inst in _active[:]:
- if inst.poll(_deadstate=sys.maxint) >= 0:
- try:
- _active.remove(inst)
- except ValueError:
- # This can happen if two threads create a new Popen instance.
- # It's harmless that it was already removed, so ignore.
- pass
-
-PIPE = -1
-STDOUT = -2
-
-
-def call(*popenargs, **kwargs):
- """Run command with arguments. Wait for command to complete, then
- return the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- retcode = call(["ls", "-l"])
- """
- return Popen(*popenargs, **kwargs).wait()
-
-
-def check_call(*popenargs, **kwargs):
- """Run command with arguments. Wait for command to complete. If
- the exit code was zero then return, otherwise raise
- CalledProcessError. The CalledProcessError object will have the
- return code in the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- check_call(["ls", "-l"])
- """
- retcode = call(*popenargs, **kwargs)
- cmd = kwargs.get("args")
- if cmd is None:
- cmd = popenargs[0]
- if retcode:
- raise CalledProcessError(retcode, cmd)
- return retcode
-
-
-def list2cmdline(seq):
- """
- Translate a sequence of arguments into a command line
- string, using the same rules as the MS C runtime:
-
- 1) Arguments are delimited by white space, which is either a
- space or a tab.
-
- 2) A string surrounded by double quotation marks is
- interpreted as a single argument, regardless of white space
- contained within. A quoted string can be embedded in an
- argument.
-
- 3) A double quotation mark preceded by a backslash is
- interpreted as a literal double quotation mark.
-
- 4) Backslashes are interpreted literally, unless they
- immediately precede a double quotation mark.
-
- 5) If backslashes immediately precede a double quotation mark,
- every pair of backslashes is interpreted as a literal
- backslash. If the number of backslashes is odd, the last
- backslash escapes the next double quotation mark as
- described in rule 3.
- """
-
- # See
- # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
- result = []
- needquote = False
- for arg in seq:
- bs_buf = []
-
- # Add a space to separate this argument from the others
- if result:
- result.append(' ')
-
- needquote = (" " in arg) or ("\t" in arg)
- if needquote:
- result.append('"')
-
- for c in arg:
- if c == '\\':
- # Don't know if we need to double yet.
- bs_buf.append(c)
- elif c == '"':
- # Double backspaces.
- result.append('\\' * len(bs_buf)*2)
- bs_buf = []
- result.append('\\"')
- else:
- # Normal char
- if bs_buf:
- result.extend(bs_buf)
- bs_buf = []
- result.append(c)
-
- # Add remaining backspaces, if any.
- if bs_buf:
- result.extend(bs_buf)
-
- if needquote:
- result.extend(bs_buf)
- result.append('"')
-
- return ''.join(result)
-
-
-class Popen(object):
- def __init__(self, args, bufsize=0, executable=None,
- stdin=None, stdout=None, stderr=None,
- preexec_fn=None, close_fds=False, shell=False,
- cwd=None, env=None, universal_newlines=False,
- startupinfo=None, creationflags=0):
- """Create new Popen instance."""
- _cleanup()
-
- self._child_created = False
- if not isinstance(bufsize, (int, long)):
- raise TypeError("bufsize must be an integer")
-
- if mswindows:
- if preexec_fn is not None:
- raise ValueError("preexec_fn is not supported on Windows "
- "platforms")
- if close_fds:
- raise ValueError("close_fds is not supported on Windows "
- "platforms")
- else:
- # POSIX
- if startupinfo is not None:
- raise ValueError("startupinfo is only supported on Windows "
- "platforms")
- if creationflags != 0:
- raise ValueError("creationflags is only supported on Windows "
- "platforms")
-
- self.stdin = None
- self.stdout = None
- self.stderr = None
- self.pid = None
- self.returncode = None
- self.universal_newlines = universal_newlines
-
- # Input and output objects. The general principle is like
- # this:
- #
- # Parent Child
- # ------ -----
- # p2cwrite ---stdin---> p2cread
- # c2pread <--stdout--- c2pwrite
- # errread <--stderr--- errwrite
- #
- # On POSIX, the child objects are file descriptors. On
- # Windows, these are Windows file handles. The parent objects
- # are file descriptors on both platforms. The parent objects
- # are None when not using PIPEs. The child objects are None
- # when not redirecting.
-
- (p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite) = self._get_handles(stdin, stdout, stderr)
-
- self._execute_child(args, executable, preexec_fn, close_fds,
- cwd, env, universal_newlines,
- startupinfo, creationflags, shell,
- p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite)
-
- if p2cwrite:
- self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
- if c2pread:
- if universal_newlines:
- self.stdout = os.fdopen(c2pread, 'rU', bufsize)
- else:
- self.stdout = os.fdopen(c2pread, 'rb', bufsize)
- if errread:
- if universal_newlines:
- self.stderr = os.fdopen(errread, 'rU', bufsize)
- else:
- self.stderr = os.fdopen(errread, 'rb', bufsize)
-
-
- def _translate_newlines(self, data):
- data = data.replace("\r\n", "\n")
- data = data.replace("\r", "\n")
- return data
-
-
- def __del__(self):
- if not self._child_created:
- # We didn't get to successfully create a child process.
- return
- # In case the child hasn't been waited on, check if it's done.
- self.poll(_deadstate=sys.maxint)
- if self.returncode is None and _active is not None:
- # Child is still running, keep us alive until we can wait on it.
- _active.append(self)
-
-
- def communicate(self, input=None):
- """Interact with process: Send data to stdin. Read data from
- stdout and stderr, until end-of-file is reached. Wait for
- process to terminate. The optional input argument should be a
- string to be sent to the child process, or None, if no data
- should be sent to the child.
-
- communicate() returns a tuple (stdout, stderr)."""
-
- # Optimization: If we are only using one pipe, or no pipe at
- # all, using select() or threads is unnecessary.
- if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
- stdout = None
- stderr = None
- if self.stdin:
- if input:
- self.stdin.write(input)
- self.stdin.close()
- elif self.stdout:
- stdout = self.stdout.read()
- elif self.stderr:
- stderr = self.stderr.read()
- self.wait()
- return (stdout, stderr)
-
- return self._communicate(input)
-
-
- if mswindows:
- #
- # Windows methods
- #
- def _get_handles(self, stdin, stdout, stderr):
- """Construct and return tupel with IO objects:
- p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
- """
- if stdin is None and stdout is None and stderr is None:
- return (None, None, None, None, None, None)
-
- p2cread, p2cwrite = None, None
- c2pread, c2pwrite = None, None
- errread, errwrite = None, None
-
- if stdin is None:
- p2cread = GetStdHandle(STD_INPUT_HANDLE)
- elif stdin == PIPE:
- p2cread, p2cwrite = CreatePipe(None, 0)
- # Detach and turn into fd
- p2cwrite = p2cwrite.Detach()
- p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
- elif isinstance(stdin, int):
- p2cread = msvcrt.get_osfhandle(stdin)
- else:
- # Assuming file-like object
- p2cread = msvcrt.get_osfhandle(stdin.fileno())
- p2cread = self._make_inheritable(p2cread)
-
- if stdout is None:
- c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
- elif stdout == PIPE:
- c2pread, c2pwrite = CreatePipe(None, 0)
- # Detach and turn into fd
- c2pread = c2pread.Detach()
- c2pread = msvcrt.open_osfhandle(c2pread, 0)
- elif isinstance(stdout, int):
- c2pwrite = msvcrt.get_osfhandle(stdout)
- else:
- # Assuming file-like object
- c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
- c2pwrite = self._make_inheritable(c2pwrite)
-
- if stderr is None:
- errwrite = GetStdHandle(STD_ERROR_HANDLE)
- elif stderr == PIPE:
- errread, errwrite = CreatePipe(None, 0)
- # Detach and turn into fd
- errread = errread.Detach()
- errread = msvcrt.open_osfhandle(errread, 0)
- elif stderr == STDOUT:
- errwrite = c2pwrite
- elif isinstance(stderr, int):
- errwrite = msvcrt.get_osfhandle(stderr)
- else:
- # Assuming file-like object
- errwrite = msvcrt.get_osfhandle(stderr.fileno())
- errwrite = self._make_inheritable(errwrite)
-
- return (p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite)
-
-
- def _make_inheritable(self, handle):
- """Return a duplicate of handle, which is inheritable"""
- return DuplicateHandle(GetCurrentProcess(), handle,
- GetCurrentProcess(), 0, 1,
- DUPLICATE_SAME_ACCESS)
-
-
- def _find_w9xpopen(self):
- """Find and return absolut path to w9xpopen.exe"""
- w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
- "w9xpopen.exe")
- if not os.path.exists(w9xpopen):
- # Eeek - file-not-found - possibly an embedding
- # situation - see if we can locate it in sys.exec_prefix
- w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
- "w9xpopen.exe")
- if not os.path.exists(w9xpopen):
- raise RuntimeError("Cannot locate w9xpopen.exe, which is "
- "needed for Popen to work with your "
- "shell or platform.")
- return w9xpopen
-
-
- def _execute_child(self, args, executable, preexec_fn, close_fds,
- cwd, env, universal_newlines,
- startupinfo, creationflags, shell,
- p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite):
- """Execute program (MS Windows version)"""
-
- if not isinstance(args, types.StringTypes):
- args = list2cmdline(args)
-
- # Process startup details
- if startupinfo is None:
- startupinfo = STARTUPINFO()
- if None not in (p2cread, c2pwrite, errwrite):
- startupinfo.dwFlags |= STARTF_USESTDHANDLES
- startupinfo.hStdInput = p2cread
- startupinfo.hStdOutput = c2pwrite
- startupinfo.hStdError = errwrite
-
- if shell:
- startupinfo.dwFlags |= STARTF_USESHOWWINDOW
- startupinfo.wShowWindow = SW_HIDE
- comspec = os.environ.get("COMSPEC", "cmd.exe")
- args = comspec + " /c " + args
- if (GetVersion() >= 0x80000000L or
- os.path.basename(comspec).lower() == "command.com"):
- # Win9x, or using command.com on NT. We need to
- # use the w9xpopen intermediate program. For more
- # information, see KB Q150956
- # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
- w9xpopen = self._find_w9xpopen()
- args = '"%s" %s' % (w9xpopen, args)
- # Not passing CREATE_NEW_CONSOLE has been known to
- # cause random failures on win9x. Specifically a
- # dialog: "Your program accessed mem currently in
- # use at xxx" and a hopeful warning about the
- # stability of your system. Cost is Ctrl+C wont
- # kill children.
- creationflags |= CREATE_NEW_CONSOLE
-
- # Start the process
- try:
- hp, ht, pid, tid = CreateProcess(executable, args,
- # no special security
- None, None,
- # must inherit handles to pass std
- # handles
- 1,
- creationflags,
- env,
- cwd,
- startupinfo)
- except pywintypes.error, e:
- # Translate pywintypes.error to WindowsError, which is
- # a subclass of OSError. FIXME: We should really
- # translate errno using _sys_errlist (or simliar), but
- # how can this be done from Python?
- raise WindowsError(*e.args)
-
- # Retain the process handle, but close the thread handle
- self._child_created = True
- self._handle = hp
- self.pid = pid
- ht.Close()
-
- # Child is launched. Close the parent's copy of those pipe
- # handles that only the child should have open. You need
- # to make sure that no handles to the write end of the
- # output pipe are maintained in this process or else the
- # pipe will not close when the child process exits and the
- # ReadFile will hang.
- if p2cread is not None:
- p2cread.Close()
- if c2pwrite is not None:
- c2pwrite.Close()
- if errwrite is not None:
- errwrite.Close()
-
-
- def poll(self, _deadstate=None):
- """Check if child process has terminated. Returns returncode
- attribute."""
- if self.returncode is None:
- if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
- self.returncode = GetExitCodeProcess(self._handle)
- return self.returncode
-
-
- def wait(self):
- """Wait for child process to terminate. Returns returncode
- attribute."""
- if self.returncode is None:
- obj = WaitForSingleObject(self._handle, INFINITE)
- self.returncode = GetExitCodeProcess(self._handle)
- return self.returncode
-
-
- def _readerthread(self, fh, buffer):
- buffer.append(fh.read())
-
-
- def _communicate(self, input):
- stdout = None # Return
- stderr = None # Return
-
- if self.stdout:
- stdout = []
- stdout_thread = threading.Thread(target=self._readerthread,
- args=(self.stdout, stdout))
- stdout_thread.setDaemon(True)
- stdout_thread.start()
- if self.stderr:
- stderr = []
- stderr_thread = threading.Thread(target=self._readerthread,
- args=(self.stderr, stderr))
- stderr_thread.setDaemon(True)
- stderr_thread.start()
-
- if self.stdin:
- if input is not None:
- self.stdin.write(input)
- self.stdin.close()
-
- if self.stdout:
- stdout_thread.join()
- if self.stderr:
- stderr_thread.join()
-
- # All data exchanged. Translate lists into strings.
- if stdout is not None:
- stdout = stdout[0]
- if stderr is not None:
- stderr = stderr[0]
-
- # Translate newlines, if requested. We cannot let the file
- # object do the translation: It is based on stdio, which is
- # impossible to combine with select (unless forcing no
- # buffering).
- if self.universal_newlines and hasattr(file, 'newlines'):
- if stdout:
- stdout = self._translate_newlines(stdout)
- if stderr:
- stderr = self._translate_newlines(stderr)
-
- self.wait()
- return (stdout, stderr)
-
- else:
- #
- # POSIX methods
- #
- def _get_handles(self, stdin, stdout, stderr):
- """Construct and return tupel with IO objects:
- p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
- """
- p2cread, p2cwrite = None, None
- c2pread, c2pwrite = None, None
- errread, errwrite = None, None
-
- if stdin is None:
- pass
- elif stdin == PIPE:
- p2cread, p2cwrite = os.pipe()
- elif isinstance(stdin, int):
- p2cread = stdin
- else:
- # Assuming file-like object
- p2cread = stdin.fileno()
-
- if stdout is None:
- pass
- elif stdout == PIPE:
- c2pread, c2pwrite = os.pipe()
- elif isinstance(stdout, int):
- c2pwrite = stdout
- else:
- # Assuming file-like object
- c2pwrite = stdout.fileno()
-
- if stderr is None:
- pass
- elif stderr == PIPE:
- errread, errwrite = os.pipe()
- elif stderr == STDOUT:
- errwrite = c2pwrite
- elif isinstance(stderr, int):
- errwrite = stderr
- else:
- # Assuming file-like object
- errwrite = stderr.fileno()
-
- return (p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite)
-
-
- def _set_cloexec_flag(self, fd):
- try:
- cloexec_flag = fcntl.FD_CLOEXEC
- except AttributeError:
- cloexec_flag = 1
-
- old = fcntl.fcntl(fd, fcntl.F_GETFD)
- fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
-
-
- def _close_fds(self, but):
- for i in xrange(3, MAXFD):
- if i == but:
- continue
- try:
- os.close(i)
- except:
- pass
-
-
- def _execute_child(self, args, executable, preexec_fn, close_fds,
- cwd, env, universal_newlines,
- startupinfo, creationflags, shell,
- p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite):
- """Execute program (POSIX version)"""
-
- if isinstance(args, types.StringTypes):
- args = [args]
-
- if shell:
- args = ["/bin/sh", "-c"] + args
-
- if executable is None:
- executable = args[0]
-
- # For transferring possible exec failure from child to parent
- # The first char specifies the exception type: 0 means
- # OSError, 1 means some other error.
- errpipe_read, errpipe_write = os.pipe()
- self._set_cloexec_flag(errpipe_write)
-
- self.pid = os.fork()
- self._child_created = True
- if self.pid == 0:
- # Child
- try:
- # Close parent's pipe ends
- if p2cwrite:
- os.close(p2cwrite)
- if c2pread:
- os.close(c2pread)
- if errread:
- os.close(errread)
- os.close(errpipe_read)
-
- # Dup fds for child
- if p2cread:
- os.dup2(p2cread, 0)
- if c2pwrite:
- os.dup2(c2pwrite, 1)
- if errwrite:
- os.dup2(errwrite, 2)
-
- # Close pipe fds. Make sure we don't close the same
- # fd more than once, or standard fds.
- if p2cread:
- os.close(p2cread)
- if c2pwrite and c2pwrite not in (p2cread,):
- os.close(c2pwrite)
- if errwrite and errwrite not in (p2cread, c2pwrite):
- os.close(errwrite)
-
- # Close all other fds, if asked for
- if close_fds:
- self._close_fds(but=errpipe_write)
-
- if cwd is not None:
- os.chdir(cwd)
-
- if preexec_fn:
- apply(preexec_fn)
-
- if env is None:
- os.execvp(executable, args)
- else:
- os.execvpe(executable, args, env)
-
- except:
- exc_type, exc_value, tb = sys.exc_info()
- # Save the traceback and attach it to the exception object
- exc_lines = traceback.format_exception(exc_type,
- exc_value,
- tb)
- exc_value.child_traceback = ''.join(exc_lines)
- os.write(errpipe_write, pickle.dumps(exc_value))
-
- # This exitcode won't be reported to applications, so it
- # really doesn't matter what we return.
- os._exit(255)
-
- # Parent
- os.close(errpipe_write)
- if p2cread and p2cwrite:
- os.close(p2cread)
- if c2pwrite and c2pread:
- os.close(c2pwrite)
- if errwrite and errread:
- os.close(errwrite)
-
- # Wait for exec to fail or succeed; possibly raising exception
- data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
- os.close(errpipe_read)
- if data != "":
- os.waitpid(self.pid, 0)
- child_exception = pickle.loads(data)
- raise child_exception
-
-
- def _handle_exitstatus(self, sts):
- if os.WIFSIGNALED(sts):
- self.returncode = -os.WTERMSIG(sts)
- elif os.WIFEXITED(sts):
- self.returncode = os.WEXITSTATUS(sts)
- else:
- # Should never happen
- raise RuntimeError("Unknown child exit status!")
-
-
- def poll(self, _deadstate=None):
- """Check if child process has terminated. Returns returncode
- attribute."""
- if self.returncode is None:
- try:
- pid, sts = os.waitpid(self.pid, os.WNOHANG)
- if pid == self.pid:
- self._handle_exitstatus(sts)
- except os.error:
- if _deadstate is not None:
- self.returncode = _deadstate
- return self.returncode
-
-
- def wait(self):
- """Wait for child process to terminate. Returns returncode
- attribute."""
- if self.returncode is None:
- pid, sts = os.waitpid(self.pid, 0)
- self._handle_exitstatus(sts)
- return self.returncode
-
-
- def _communicate(self, input):
- read_set = []
- write_set = []
- stdout = None # Return
- stderr = None # Return
-
- if self.stdin:
- # Flush stdio buffer. This might block, if the user has
- # been writing to .stdin in an uncontrolled fashion.
- self.stdin.flush()
- if input:
- write_set.append(self.stdin)
- else:
- self.stdin.close()
- if self.stdout:
- read_set.append(self.stdout)
- stdout = []
- if self.stderr:
- read_set.append(self.stderr)
- stderr = []
-
- while read_set or write_set:
- rlist, wlist, xlist = select.select(read_set, write_set, [])
-
- if self.stdin in wlist:
- # When select has indicated that the file is writable,
- # we can write up to PIPE_BUF bytes without risk
- # blocking. POSIX defines PIPE_BUF >= 512
- bytes_written = os.write(self.stdin.fileno(), input[:512])
- input = input[bytes_written:]
- if not input:
- self.stdin.close()
- write_set.remove(self.stdin)
-
- if self.stdout in rlist:
- data = os.read(self.stdout.fileno(), 1024)
- if data == "":
- self.stdout.close()
- read_set.remove(self.stdout)
- stdout.append(data)
-
- if self.stderr in rlist:
- data = os.read(self.stderr.fileno(), 1024)
- if data == "":
- self.stderr.close()
- read_set.remove(self.stderr)
- stderr.append(data)
-
- # All data exchanged. Translate lists into strings.
- if stdout is not None:
- stdout = ''.join(stdout)
- if stderr is not None:
- stderr = ''.join(stderr)
-
- # Translate newlines, if requested. We cannot let the file
- # object do the translation: It is based on stdio, which is
- # impossible to combine with select (unless forcing no
- # buffering).
- if self.universal_newlines and hasattr(file, 'newlines'):
- if stdout:
- stdout = self._translate_newlines(stdout)
- if stderr:
- stderr = self._translate_newlines(stderr)
-
- self.wait()
- return (stdout, stderr)
-
-
-def _demo_posix():
- #
- # Example 1: Simple redirection: Get process list
- #
- plist = Popen(["ps"], stdout=PIPE).communicate()[0]
- print "Process list:"
- print plist
-
- #
- # Example 2: Change uid before executing child
- #
- if os.getuid() == 0:
- p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
- p.wait()
-
- #
- # Example 3: Connecting several subprocesses
- #
- print "Looking for 'hda'..."
- p1 = Popen(["dmesg"], stdout=PIPE)
- p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
- print repr(p2.communicate()[0])
-
- #
- # Example 4: Catch execution error
- #
- print
- print "Trying a weird file..."
- try:
- print Popen(["/this/path/does/not/exist"]).communicate()
- except OSError, e:
- if e.errno == errno.ENOENT:
- print "The file didn't exist. I thought so..."
- print "Child traceback:"
- print e.child_traceback
- else:
- print "Error", e.errno
- else:
- print >>sys.stderr, "Gosh. No error."
-
-
-def _demo_windows():
- #
- # Example 1: Connecting several subprocesses
- #
- print "Looking for 'PROMPT' in set output..."
- p1 = Popen("set", stdout=PIPE, shell=True)
- p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
- print repr(p2.communicate()[0])
-
- #
- # Example 2: Simple execution of program
- #
- print "Executing calc..."
- p = Popen("calc")
- p.wait()
-
-
-if __name__ == "__main__":
- if mswindows:
- _demo_windows()
- else:
- _demo_posix()
diff --git a/func/minion/utils.py b/func/minion/utils.py
deleted file mode 100755
index a7ea788..0000000
--- a/func/minion/utils.py
+++ /dev/null
@@ -1,207 +0,0 @@
-"""
-Copyright 2007, Red Hat, Inc
-see AUTHORS
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-import os
-import socket
-import string
-import sys
-import time
-import traceback
-import xmlrpclib
-import glob
-import traceback
-
-import codes
-from func import certs
-from func.config import read_config
-from func.commonconfig import FuncdConfig
-from func import logger
-
-# "localhost" is a lame hostname to use for a key, so try to get
-# a more meaningful hostname. We do this by connecting to the certmaster
-# and seeing what interface/ip it uses to make that connection, and looking
-# up the hostname for that.
-def get_hostname():
-
- # FIXME: this code ignores http proxies (which granted, we don't
- # support elsewhere either. It also hardcodes the port number
- # for the certmaster for now
- hostname = None
- hostname = socket.gethostname()
- try:
- ip = socket.gethostbyname(hostname)
- except:
- return hostname
- if ip != "127.0.0.1":
- return hostname
-
-
- config_file = '/etc/func/minion.conf'
- config = read_config(config_file, FuncdConfig)
-
- server = config.certmaster
- port = 51235
-
- try:
- s = socket.socket()
- s.settimeout(5)
- s.connect((server, port))
- (intf, port) = s.getsockname()
- hostname = socket.gethostbyaddr(intf)[0]
- s.close()
- except:
- s.close()
- raise
-
- return hostname
-
-
-
-def create_minion_keys():
- config_file = '/etc/func/minion.conf'
- config = read_config(config_file, FuncdConfig)
- cert_dir = config.cert_dir
- master_uri = 'http://%s:51235/' % config.certmaster
- hn = get_hostname()
-
- if hn is None:
- raise codes.FuncException("Could not determine a hostname other than localhost")
-
- key_file = '%s/%s.pem' % (cert_dir, hn)
- csr_file = '%s/%s.csr' % (cert_dir, hn)
- cert_file = '%s/%s.cert' % (cert_dir, hn)
- ca_cert_file = '%s/ca.cert' % cert_dir
-
-
- if os.path.exists(cert_file) and os.path.exists(ca_cert_file):
- return
-
- keypair = None
- try:
- if not os.path.exists(cert_dir):
- os.makedirs(cert_dir)
- if not os.path.exists(key_file):
- keypair = certs.make_keypair(dest=key_file)
- if not os.path.exists(csr_file):
- if not keypair:
- keypair = certs.retrieve_key_from_file(key_file)
- csr = certs.make_csr(keypair, dest=csr_file)
- except Exception, e:
- traceback.print_exc()
- raise codes.FuncException, "Could not create local keypair or csr for minion funcd session"
-
- result = False
- log = logger.Logger().logger
- while not result:
- try:
- log.debug("submitting CSR to certmaster %s" % master_uri)
- result, cert_string, ca_cert_string = submit_csr_to_master(csr_file, master_uri)
- except socket.gaierror, e:
- raise codes.FuncException, "Could not locate certmaster at %s" % master_uri
-
- # logging here would be nice
- if not result:
- log.warning("no response from certmaster %s, sleeping 10 seconds" % master_uri)
- time.sleep(10)
-
-
- if result:
- log.debug("received certificate from certmaster %s, storing" % master_uri)
- cert_fd = os.open(cert_file, os.O_RDWR|os.O_CREAT, 0644)
- os.write(cert_fd, cert_string)
- os.close(cert_fd)
-
- ca_cert_fd = os.open(ca_cert_file, os.O_RDWR|os.O_CREAT, 0644)
- os.write(ca_cert_fd, ca_cert_string)
- os.close(ca_cert_fd)
-
-def submit_csr_to_master(csr_file, master_uri):
- """"
- gets us our cert back from the certmaster.wait_for_cert() method
- takes csr_file as path location and master_uri
- returns Bool, str(cert), str(ca_cert)
- """
-
- fo = open(csr_file)
- csr = fo.read()
- s = xmlrpclib.ServerProxy(master_uri)
-
- return s.wait_for_cert(csr)
-
-
-# this is kind of handy, so keep it around for now
-# but we really need to fix out server side logging and error
-# reporting so we don't need it
-def trace_me():
- x = traceback.extract_stack()
- bar = string.join(traceback.format_list(x))
- return bar
-
-
-def daemonize(pidfile=None):
- """
- Daemonize this process with the UNIX double-fork trick.
- Writes the new PID to the provided file name if not None.
- """
-
- print pidfile
- pid = os.fork()
- if pid > 0:
- sys.exit(0)
- os.setsid()
- os.umask(0)
- pid = os.fork()
-
-
- if pid > 0:
- if pidfile is not None:
- open(pidfile, "w").write(str(pid))
- sys.exit(0)
-
-def get_acls_from_config(acldir='/etc/func/minion-acl.d'):
- """
- takes a dir of .acl files
- returns a dict of hostname+hash = [methods, to, run]
-
- """
-
- acls = {}
- if not os.path.exists(acldir):
- print 'acl dir does not exist: %s' % acldir
- return acls
-
- # get the set of files
- acl_glob = '%s/*.acl' % acldir
- files = glob.glob(acl_glob)
-
- for acl_file in files:
-
- try:
- fo = open(acl_file, 'r')
- except (IOError, OSError), e:
- print 'cannot open acl config file: %s - %s' % (acl_file, e)
- continue
-
- for line in fo.readlines():
- if line.startswith('#'): continue
- if line.strip() == '': continue
- line = line.replace('\n', '')
- (host, methods) = line.split('=')
- host = host.strip().lower()
- methods = methods.strip()
- methods = methods.replace(',',' ')
- methods = methods.split()
- if not acls.has_key(host):
- acls[host] = []
- acls[host].extend(methods)
-
- return acls