return False
-class Func_Client_Exception(Exception):
+# FIXME: is anything using this? remove underscores
+class CertMaster_Client_Exception(Exception):
def __init__(self, value=None):
Exception.__init__(self)
self.value = value
def_country = 'UN'
def_state = 'FC'
-def_local = 'Func-ytown'
-def_org = 'func'
+def_local = 'Certmaster-town'
+def_org = 'certmaster'
def_ou = 'slave-key'
return cert
-def create_ca(CN="Func Certificate Authority", ca_key_file=None, ca_cert_file=None):
+def create_ca(CN="Certmaster Certificate Authority", ca_key_file=None, ca_cert_file=None):
cakey = make_keypair(dest=ca_key_file)
careq = make_csr(cakey, cn=CN)
cacert = crypto.X509()
"""
-func
+Certmaster
-Copyright 2007, Red Hat, Inc
+Copyright 2007-2008, Red Hat, Inc
See AUTHORS
This software may be freely redistributed under the terms of the GNU
import exceptions
-class FuncException(exceptions.Exception):
+class CertMasterException(exceptions.Exception):
pass
-class InvalidMethodException(FuncException):
+class InvalidMethodException(CertMasterException):
pass
# FIXME: more sub-exceptions maybe
+
class CMConfig(BaseConfig):
listen_addr = Option('')
- cadir = Option('/etc/pki/func/ca')
- certroot = Option('/var/lib/func/certmaster/certs')
- csrroot = Option('/var/lib/func/certmaster/csrs')
+ cadir = Option('/etc/pki/certmaster/ca')
+ certroot = Option('/var/lib/certmaster/certmaster/certs')
+ csrroot = Option('/var/lib/certmaster/certmaster/csrs')
autosign = BoolOption(False)
class FuncdConfig(BaseConfig):
log_level = Option('INFO')
certmaster = Option('certmaster')
- cert_dir = Option('/etc/pki/func')
- acl_dir = Option('/etc/func/minion-acl.d')
+ cert_dir = Option('/etc/pki/certmaster')
+ acl_dir = Option('/etc/certmaster/minion-acl.d')
from ConfigParser import ParsingError
import exceptions
-CONFIG_FILE = "/etc/func/certmaster.conf"
+CONFIG_FILE = "/etc/certmaster/certmaster.conf"
class ConfigError(exceptions.Exception):
def __init__(self, value=None):
+++ /dev/null
-# forkbomb is a module that partitions arbitrary workloads
-# among N seperate forks, for a configurable N, and
-# collates results upon return, as if it never forked.
-#
-# 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 os
-import random # for testing only
-import time # for testing only
-import shelve
-import bsddb
-import sys
-import tempfile
-import fcntl
-import utils
-import xmlrpclib
-
-DEFAULT_FORKS = 4
-DEFAULT_CACHE_DIR = "/var/lib/func"
-
-def __get_storage(dir):
- """
- Return a tempfile we can use for storing data.
- """
- dir = os.path.expanduser(dir)
- if not os.path.exists(dir):
- os.makedirs(dir)
- return tempfile.mktemp(suffix='', prefix='asynctmp', dir=dir)
-
-def __access_buckets(filename,clear,new_key=None,new_value=None):
- """
- Access data in forkbomb cache, potentially clearing or
- modifying it as required.
- """
-
- internal_db = bsddb.btopen(filename, 'c', 0644 )
- handle = open(filename,"r")
- fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
- storage = shelve.BsdDbShelf(internal_db)
-
- if clear:
- storage.clear()
- storage.close()
- fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
- return {}
-
- if not storage.has_key("data"):
- storage["data"] = {}
- else:
- pass
-
- if new_key is not None:
- # bsdb is a bit weird about this
- newish = storage["data"].copy()
- newish[new_key] = new_value
- storage["data"] = newish
-
- rc = storage["data"].copy()
- storage.close()
- fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
-
- return rc
-
-def __bucketize(pool, slots):
- """
- Given a pre-existing list of X number of tasks, partition
- them into a hash of Y number of slots.
- """
- buckets = {}
- count = 0
- for key in pool:
- count = count + 1
- slot = count % slots
- if not buckets.has_key(slot):
- buckets[slot] = []
- buckets[slot].append(key)
- return buckets
-
-def __with_my_bucket(bucket_number,buckets,what_to_do,filename):
- """
- Process all tasks assigned to a given fork, and save
- them in the shelf.
- """
- things_in_my_bucket = buckets[bucket_number]
- results = {}
- for thing in things_in_my_bucket:
- (nkey,nvalue) = what_to_do(bucket_number,buckets,thing)
- __access_buckets(filename,False,nkey,nvalue)
-
-def __forkbomb(mybucket,buckets,what_to_do,filename):
- """
- Recursive function to spawn of a lot of worker forks.
- """
- nbuckets = len(buckets)
- pid = os.fork()
- if pid != 0:
- if mybucket < (nbuckets-1):
- __forkbomb(mybucket+1,buckets,what_to_do,filename)
- try:
- os.waitpid(pid,0)
- except OSError, ose:
- if ose.errno == 10:
- pass
- else:
- raise ose
- else:
- __with_my_bucket(mybucket,buckets,what_to_do,filename)
- sys.exit(0)
-
-def __demo(bucket_number, buckets, my_item):
- """
- This is a demo handler for test purposes.
- It just multiplies all numbers by 1000, but slowly.
- """
- # print ">> I am fork (%s) and I am processing item (%s)" % (bucket_number, my_item)
- # just to verify forks are not sequential
- sleep = random.randrange(0,4)
- time.sleep(sleep)
- return (my_item, my_item * 1000)
-
-def batch_run(pool,callback,nforks=DEFAULT_FORKS,cachedir=DEFAULT_CACHE_DIR):
- """
- Given an array of items (pool), call callback in each one, but divide
- the workload over nfork forks. Temporary files used during the
- operation will be created in cachedir and subsequently deleted.
- """
- if nforks <= 1:
- # modulus voodoo gets crazy otherwise and bad things happen
- nforks = 2
- shelf_file = __get_storage(cachedir)
- __access_buckets(shelf_file,True,None)
- buckets = __bucketize(pool, nforks)
- __forkbomb(1,buckets,callback,shelf_file)
- rc = __access_buckets(shelf_file,False,None)
- os.remove(shelf_file)
- return rc
-
-def __test(nforks=4,sample_size=20):
- pool = xrange(0,sample_size)
- print batch_run(pool,__demo,nforks=nforks)
-
-if __name__ == "__main__":
- __test()
-
-
+++ /dev/null
-# jobthing is a module that allows for background execution of a task, and
-# getting status of that task. The ultimate goal is to allow ajaxyness
-# of GUI apps using Func, and also for extremely long running tasks that
-# we don't want to block on as called by scripts using the FunC API. The
-# CLI should not use this.
-#
-# 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 os
-import random # for testing only
-import time # for testing only
-import shelve
-import bsddb
-import sys
-import tempfile
-import fcntl
-import forkbomb
-import utils
-import traceback
-
-JOB_ID_RUNNING = 0
-JOB_ID_FINISHED = 1
-JOB_ID_LOST_IN_SPACE = 2
-JOB_ID_ASYNC_PARTIAL = 3
-JOB_ID_ASYNC_FINISHED = 4
-
-# how long to retain old job records in the job id database
-RETAIN_INTERVAL = 60 * 60
-
-# where to store the internal job id database
-CACHE_DIR = "/var/lib/func"
-
-def __update_status(jobid, status, results, clear=False):
- return __access_status(jobid=jobid, status=status, results=results, write=True)
-
-def __get_status(jobid):
- return __access_status(jobid=jobid, write=False)
-
-def purge_old_jobs():
- return __access_status(purge=True)
-
-def __purge_old_jobs(storage):
- """
- Deletes jobs older than RETAIN_INTERVAL seconds.
- MINOR FIXME: this probably should be a more intelligent algorithm that only
- deletes jobs if the database is too big and then only the oldest jobs
- but this will work just as well.
- """
- nowtime = time.time()
- for x in storage.keys():
- # minion jobs have "-minion" in the job id so disambiguation so we need to remove that
- jobkey = x.replace("-","").replace("minion","")
- create_time = float(jobkey)
- if nowtime - create_time > RETAIN_INTERVAL:
- del storage[x]
-
-def __access_status(jobid=0, status=0, results=0, clear=False, write=False, purge=False):
-
- dir = os.path.expanduser(CACHE_DIR)
- if not os.path.exists(dir):
- os.makedirs(dir)
- filename = os.path.join(dir,"status-%s" % os.getuid())
-
- internal_db = bsddb.btopen(filename, 'c', 0644 )
- handle = open(filename,"r")
- fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
- storage = shelve.BsdDbShelf(internal_db)
-
-
- if clear:
- storage.clear()
- storage.close()
- fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
- return {}
-
- if purge or write:
- __purge_old_jobs(storage)
-
- if write:
- storage[str(jobid)] = (status, results)
- rc = jobid
- elif not purge:
- if storage.has_key(str(jobid)):
- # tuple of (status, results)
-
- rc = storage[str(jobid)]
- else:
- rc = (JOB_ID_LOST_IN_SPACE, 0)
- else:
- rc = 0
-
- storage.close()
- fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
-
- return rc
-
-def batch_run(server, process_server, nforks):
- """
- This is the method used by the overlord side usage of jobthing.
- Minion side usage will use minion_async_run instead.
-
- Given an array of items (pool), call callback in each one, but divide
- the workload over nfork forks. Temporary files used during the
- operation will be created in cachedir and subsequently deleted.
- """
-
- job_id = time.time()
- pid = os.fork()
- if pid != 0:
- __update_status(job_id, JOB_ID_RUNNING, -1)
- return job_id
- else:
- # kick off the job
- __update_status(job_id, JOB_ID_RUNNING, -1)
- results = forkbomb.batch_run(server, process_server, nforks)
-
- # we now have a list of job id's for each minion, kill the task
- __update_status(job_id, JOB_ID_ASYNC_PARTIAL, results)
- sys.exit(0)
-
-def minion_async_run(retriever, method, args):
- """
- This is a simpler invocation for minion side async usage.
- """
- # to avoid confusion of job id's (we use the same job database)
- # minion jobs contain the string "minion".
-
-
- job_id = "%s-minion" % time.time()
- pid = os.fork()
- if pid != 0:
- __update_status(job_id, JOB_ID_RUNNING, -1)
- return job_id
- else:
- __update_status(job_id, JOB_ID_RUNNING, -1)
- try:
- function_ref = retriever(method)
- rc = function_ref(*args)
- except Exception, e:
- (t, v, tb) = sys.exc_info()
- rc = utils.nice_exception(t,v,tb)
-
- __update_status(job_id, JOB_ID_FINISHED, rc)
- sys.exit(0)
-
-def job_status(jobid, client_class=None):
-
- # NOTE: client_class is here to get around some evil circular reference
- # type stuff. This is intended to be called by minions (who can leave it None)
- # or by the Client module code (which does not need to be worried about it). API
- # users should not be calling jobthing.py methods directly.
-
- got_status = __get_status(jobid)
-
- # if the status comes back as JOB_ID_ASYNC_PARTIAL what we have is actually a hash
- # of hostname/minion-jobid pairs. Instantiate a client handle for each and poll them
- # for their actual status, filling in only the ones that are actually done.
-
- (interim_rc, interim_results) = got_status
-
- if interim_rc == JOB_ID_ASYNC_PARTIAL:
-
- partial_results = {}
-
-
- some_missing = False
- for host in interim_results.keys():
-
- minion_job = interim_results[host]
- client = client_class(host, noglobs=True, async=False)
- minion_result = client.jobs.job_status(minion_job)
-
- (minion_interim_rc, minion_interim_result) = minion_result
-
- if minion_interim_rc not in [ JOB_ID_RUNNING ]:
- if minion_interim_rc in [ JOB_ID_LOST_IN_SPACE ]:
- partial_results[host] = [ utils.REMOTE_ERROR, "lost job" ]
- else:
- partial_results[host] = minion_interim_result
- else:
- some_missing = True
-
- if some_missing:
- return (JOB_ID_ASYNC_PARTIAL, partial_results)
- else:
- return (JOB_ID_ASYNC_FINISHED, partial_results)
-
- else:
- return got_status
-
- # of job id's on the minion in results.
-
-if __name__ == "__main__":
- __test()
-
-
-## func
+## Certmaster
##
## Copyright 2007, Red Hat, Inc
## See AUTHORS
import logging
-from func.config import read_config
-from func.commonconfig import FuncdConfig
+from certmaster.config import read_config
+from certmaster.commonconfig import CertmasterConfig
# from the comments in http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531
class Logger(Singleton):
_no_handlers = True
- def __init__(self, logfilepath ="/var/log/func/func.log"):
- config_file = '/etc/func/minion.conf'
- self.config = read_config(config_file, FuncdConfig)
+ def __init__(self, logfilepath ="/var/log/certmaster/certmaster.log"):
+ config_file = '/etc/certmaster/minion.conf'
+ self.config = read_config(config_file, CertMasterConfig)
self.loglevel = logging._levelNames[self.config.log_level]
self._setup_logging()
if self._no_handlers:
def _setup_logging(self):
self.logger = logging.getLogger("svc")
- def _setup_handlers(self, logfilepath="/var/log/func/func.log"):
+ def _setup_handlers(self, logfilepath="/var/log/certmaster/certmaster.log"):
handler = logging.FileHandler(logfilepath, "a")
self.logger.setLevel(self.loglevel)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
class AuditLogger(Singleton):
_no_handlers = True
- def __init__(self, logfilepath = "/var/log/func/audit.log"):
+ def __init__(self, logfilepath = "/var/log/certmaster/audit.log"):
self.loglevel = logging.INFO
self._setup_logging()
if self._no_handlers:
def _setup_logging(self):
self.logger = logging.getLogger("audit")
- def _setup_handlers(self, logfilepath="/var/log/func/audit.log"):
+ def _setup_handlers(self, logfilepath="/var/log/certmaster/audit.log"):
handler = logging.FileHandler(logfilepath, "a")
self.logger.setLevel(self.loglevel)
formatter = logging.Formatter("%(asctime)s - %(message)s")
+++ /dev/null
-## 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()
+++ /dev/null
-
-
-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
+++ /dev/null
-## -*- 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 ]
-
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-## 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()
+++ /dev/null
-##
-## 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
+++ /dev/null
-##
-## 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
+++ /dev/null
-##
-## 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
+++ /dev/null
-## (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)
-
+++ /dev/null
-##
-## 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()
+++ /dev/null
-# 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])
+++ /dev/null
-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
+++ /dev/null
-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!
+++ /dev/null
-##
-## 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
-
+++ /dev/null
-##
-## 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
-
+++ /dev/null
-##
-## 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
+++ /dev/null
-##
-## 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)
-
-
-
+++ /dev/null
-# 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')]
+++ /dev/null
-## -*- 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
+++ /dev/null
-## -*- 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
+++ /dev/null
-# 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])
+++ /dev/null
-# 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
+++ /dev/null
-## 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
+++ /dev/null
-##
-## 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)
+++ /dev/null
-# 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):
+++ /dev/null
-# 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))
+++ /dev/null
-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!!!!!!")
+++ /dev/null
-"""
-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)
+++ /dev/null
-# 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)
+++ /dev/null
-"""
-call func method invoker
-
-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 optparse
-import pprint
-import xmlrpclib
-
-from func.overlord import command
-from func.overlord import client
-
-DEFAULT_PORT = 51234
-DEFAULT_FORKS = 1
-
-class Call(client.command.Command):
- name = "call"
- usage = "call module method name arg1 arg2..."
- def addOptions(self):
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
- self.parser.add_option("-x", "--xmlrpc", dest="xmlrpc",
- help="output return data in XMLRPC format",
- action="store_true")
- self.parser.add_option("", "--raw", dest="rawprint",
- help="output return data using Python print",
- action="store_true")
- self.parser.add_option("-j", "--json", dest="json",
- help="output return data using JSON",
- action="store_true")
- self.parser.add_option("-p", "--port", dest="port",
- default=DEFAULT_PORT)
- self.parser.add_option("-f", "--forks", dest="forks",
- help="how many parallel processes? (default 1)",
- default=DEFAULT_FORKS)
-
- def handleOptions(self, options):
- self.options = options
-
- self.verbose = options.verbose
- self.port = options.port
-
- # I'm not really a fan of the "module methodname" approach
- # but we'll keep it for now -akl
-
- def parse(self, argv):
- self.argv = argv
-
- return command.Command.parse(self, argv)
-
-
- def format_return(self, data):
- """
- The call module supports multiple output return types, the default is pprint.
- """
-
- if self.options.xmlrpc:
- return xmlrpclib.dumps((data,""))
-
- if self.options.json:
- try:
- import simplejson
- return simplejson.dumps(data)
- except ImportError:
- print "WARNING: json support not found, install python-simplejson"
- return data
-
- if self.options.rawprint:
- return data
-
- return pprint.pformat(data)
-
- def do(self, args):
-
- # I'm not really a fan of the "module methodname" approach
- # but we'll keep it for now -akl
-
- # I kind of feel like we shouldn't be parsing args here, but I'm
- # not sure what the write place is -al;
- self.module = args[0]
- if len(args) > 1:
- self.method = args[1]
- else:
- self.method = None
- if len(args) > 2:
- self.method_args = args[2:]
- else:
- self.method_args = []
-
- # this could get weird, sub sub classes might be calling this
- # this with multiple.parentCommand.parentCommands...
- # maybe command.py needs a way to set attrs on subCommands?
- # or some sort of shared datastruct?
- self.server_spec = self.parentCommand.server_spec
-
- client_obj = client.Client(self.server_spec,port=self.port,interactive=True,
- verbose=self.verbose, config=self.config, nforks=self.options.forks)
- results = client_obj.run(self.module, self.method, self.method_args)
-
- # TO DO: add multiplexer support
- # probably as a higher level module.
-
- # dump the return code stuff atm till we figure out the right place for it
- return self.format_return(results)
+++ /dev/null
-"""
-copyfile command line
-
-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 optparse
-import os
-import pprint
-import stat
-import xmlrpclib
-
-from func.overlord import command
-from func.overlord import client
-
-DEFAULT_PORT = 51234
-
-class CopyFile(client.command.Command):
- name = "copyfile"
- usage = "copy a file to a client"
-
-
- def addOptions(self):
- self.parser.add_option("-f", "--file", dest="filename",
- action="store")
- self.parser.add_option("", "--remotepath", dest="remotepath",
- action="store")
- self.parser.add_option("", "--force", dest="force",
- action="store_true")
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
- self.parser.add_option("-p", "--port", dest="port")
-
- def handleOptions(self, options):
- self.port = DEFAULT_PORT
- if self.options.port:
- self.port = self.options.port
-
-
- def do(self, args):
- self.server_spec = self.parentCommand.server_spec
-
- client_obj = client.Client(self.server_spec,
- port=self.port,
- interactive=False,
- verbose=self.options.verbose,
- config=self.config)
-
-
- try:
- fb = open(self.options.filename, "r").read()
- except IOError, e:
- print "Unable to open file: %s: %s" % (self.options.filename, e)
- return
-
- st = os.stat(self.options.filename)
- mode = stat.S_IMODE(st.st_mode)
- uid = st.st_uid
- gid = st.st_gid
-
-
- data = xmlrpclib.Binary(fb)
- results = client_obj.run("copyfile", "copyfile", [self.options.remotepath, data,
- mode, uid, gid])
+++ /dev/null
-"""
-copyfile command line
-
-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 optparse
-import os
-
-from func.overlord import command
-from func.overlord import client
-DEFAULT_PORT = 51234
-
-class ListMinions(client.command.Command):
- name = "list_minions"
- usage = "show known minions"
-
- def addOptions(self):
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
-
- def handleOptions(self, options):
- self.port = DEFAULT_PORT
- if options.verbose:
- self.verbose = self.options.verbose
-
- def do(self, args):
- self.server_spec = self.parentCommand.server_spec
-
- client_obj = client.Client(self.server_spec,
- port=self.port,
- interactive=False,
- verbose=self.options.verbose,
- config=self.config)
-
- servers = client_obj.servers
- print servers
- for server in servers:
- # just cause I hate regex'es -akl
- host = server.split(':')[-2]
- host = host.split('/')[-1]
- print host
+++ /dev/null
-"""
-copyfile command line
-
-Copyright 2007, Red Hat, Inc
-Michael DeHaan <mdehaan@redhat.com>
-also 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 optparse
-import os
-import pprint
-import stat
-import xmlrpclib
-
-from func.overlord import command
-from func.overlord import client
-
-# FIXME: this really should not be in each sub module.
-DEFAULT_PORT = 51234
-
-
-class Ping(client.command.Command):
- name = "ping"
- usage = "see what func minions are up/accessible"
-
- def addOptions(self):
- """
- Not too many options for you! (Seriously, it's a simple command ... func "*" ping)
- """
- # FIXME: verbose and port should be added globally to all sub modules
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
- self.parser.add_option("-p", "--port", dest="port",
- default=DEFAULT_PORT)
-
- def handleOptions(self, options):
- """
- Nothing to do here...
- """
- pass
-
- def do(self, args):
- self.server_spec = self.parentCommand.server_spec
-
- # because this is mainly an interactive command, expand the server list and make seperate connections.
- # to make things look more speedy.
-
- servers = client.expand_servers(self.server_spec, port=self.options.port, noglobs=None,
- verbose=self.options.verbose, just_fqdns=True)
-
- for server in servers:
-
- client_obj = client.Client(server,port=self.options.port,interactive=False,
- verbose=self.options.verbose,config=self.config, noglobs=True)
-
- results = client_obj.run("test", "ping", [])
- if results == 1:
- print "[ ok ... ] %s" % server
- else:
- print "[ FAILED ] %s" % server
-
- return 1
+++ /dev/null
-"""
-show introspection commandline
-
-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 optparse
-import pprint
-import xmlrpclib
-
-from func.overlord import command
-from func.overlord import client
-
-DEFAULT_PORT = 51234
-
-
-class ShowHardware(client.command.Command):
- name = "hardware"
- usage = "show hardware details"
-
- # FIXME: we might as well make verbose be in the subclass
- # and probably an inc variable while we are at it
- def addOptions(self):
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
- self.parser.add_option("-p", "--port", dest="port")
-
-
- def handleOptions(self, options):
- self.port = DEFAULT_PORT
- if self.options.port:
- self.port = self.options.port
-
- def parse(self, argv):
- self.argv = argv
- return command.Command.parse(self,argv)
-
- def do(self,args):
-
- self.server_spec = self.parentCommand.parentCommand.server_spec
-
- client_obj = client.Client(self.server_spec,
- port=self.port,
- interactive=False,
- verbose=self.options.verbose,
- config=self.config)
-
- results = client_obj.run("hardware", "info", [])
-
- # if the user
- top_options = ["port","verbose"]
-
- for minion in results:
- print "%s:" % minion
- minion_data = results[minion]
- # if user set no args
- if not args:
- pprint.pprint(minion_data)
- continue
-
- for arg in args:
- if arg in minion_data:
- print minion_data[arg]
-
-
-class Show(client.command.Command):
- name = "show"
- usage = "various simple report stuff"
- subCommandClasses = [ShowHardware]
- def addOptions(self):
- self.parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true")
- self.parser.add_option("-p", "--port", dest="port",
- default=DEFAULT_PORT)
-
- def handleOptions(self, options):
- self.options = options
-
- self.verbose = options.verbose
- self.port = options.port
-
-
- def parse(self, argv):
- self.argv = argv
-
- return command.Command.parse(self, argv)
-
-
- def do(self, args):
- pass
+++ /dev/null
-##
-## Overlord library to interface with minion-side netapp operations
-##
-## Most of this is just wrappers to create some cleaner, earier to use
-## interfaces. Also allows users to get function signatures and use
-## nice things like kwargs client side, for those of us who can't live
-## without ipython introspection.
-##
-## 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.
-##
-
-from func.overlord.client import Client
-
-class RemoteError(Exception): pass
-
-def _(res):
- if type(res) == type([]) and res[0] == 'REMOTE_ERROR':
- raise RemoteError, res[2]
- else:
- return res
-
-class Filer(Client):
- def __init__(self, filer, admin_host):
- Client.__init__(self, admin_host)
- self.filer = filer
- self.admin_host = admin_host
-
- def create_volume(self, vol, aggr, size):
- return _(self.netapp.vol.create(self.filer, vol, aggr, size)[self.admin_host])
-
- def destroy_volume(self, vol):
- # offline it first
- try:
- self.netapp.vol.offline(self.filer, vol)
- except:
- pass
- return _(self.netapp.vol.destroy(self.filer, vol)[self.admin_host])
-
- def offline_volume(self, vol):
- return _(self.netapp.vol.offline(self.filer, vol)[self.admin_host])
-
- def online_volume(self, vol):
- return _(self.netapp.vol.online(self.filer, vol)[self.admin_host])
-
- def get_volume_size(self, vol):
- return _(self.netapp.vol.size(self.filer, vol)[self.admin_host])
-
- def resize_volume(self, vol, delta):
- return _(self.netapp.vol.size(self.filer, vol, delta)[self.admin_host])
-
- def create_snapshot(self, vol, snap):
- return _(self.netapp.snap.create(self.filer, vol, snap)[self.admin_host])
-
- def delete_snapshot(self, vol, snap):
- return _(self.netapp.snap.delete(self.filer, vol, snap)[self.admin_host])
-
- def create_clone_volume(self, vol, parent, snap):
- return _(self.netapp.vol.clone.create(self.filer, vol, parent, snap)[self.admin_host])
-
- def split_clone_volume(self, vol):
- return _(self.netapp.vol.clone.split(self.filer, vol)[self.admin_host])
-
- def list_volumes(self):
- vols = _(self.netapp.vol.status(self.filer))
- return_list = []
- for vol in vols:
- return_list.append(vol['name'])
- return return_list
-
- def volume_details(self, vol=None):
- if vol:
- return _(self.netapp.vol.status(self.filer, vol)[self.admin_host])
- else:
- return _(self.netapp.vol.status(self.filer)[self.admin_host])
+++ /dev/null
-#!/usr/bin/python
-
-
-# FIXME: should import the client lib, not XMLRPC lib, when we are done
-
-import xmlrpclib
-import sys
-
-TEST_GETATTR = True
-TEST_PROCESS = False
-TEST_VIRT = False
-TEST_SERVICES = False
-TEST_HARDWARE = False
-TEST_SMART = True
-
-if TEST_GETATTR:
- import func.overlord.client as func_client
- print func_client.Client("*").hardware.pci_info()
- #print func_client.Client("*").test.add(1,2)
- #print func_client.Client("*").hardware.info()
- #print func_client.Client("*").run("hardware","info",[])
- #print func_client.Client(socket.gethostname(),noglobs=True).test.add("1","2")
- sys.exit(1)
-
-# get a connecton (to be replaced by client lib logic)
-s = xmlrpclib.ServerProxy("http://127.0.0.1:51234")
-
-# here's the basic test...
-print s.test.add(1, 2)
-
-if TEST_SMART:
- print s.smart.info()
-
-if TEST_PROCESS:
- print s.process.info()
- # print s.process.pkill("thunderbird")
-
-# here's the service module testing
-if TEST_SERVICES:
- print s.service.restart("httpd")
-
-if TEST_HARDWARE:
- print s.hardware.info()
-
-# this is so I can remember how the virt module works
-if TEST_VIRT:
-
- # example of using koan to install a virtual machine
- #s.virt_install("mdehaan.rdu.redhat.com","profileX")
-
- # wait ...
- vms = s.virt.list_vms()
- # example of stopping all stopped virtual machines
- print "list of virtual instances = %s" % vms
- for vm in vms:
- status = s.virt.status(vm)
- print status
- if status == "shutdown":
- s.virt.start(vm)
-
-# add more tests here
"""
-Copyright 2007, Red Hat, Inc
+Copyright 2007-2008, Red Hat, Inc
see AUTHORS
This software may be freely redistributed under the terms of the GNU