#!/usr/bin/env python # $Id: lava.rc.py 154 2009-02-25 04:52:41Z mkchew $ # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # import pwd from path import path from kusu.core import rcplugin # Change this to 1 to see debug logs in /var/log/kusu/kusu.log DEBUG = 0 MASTER_COMPONENT = "component-lava-master-v1_0" COMPUTE_COMPONENT = "component-lava-compute-v1_0" KIT_COMPONENTS = (MASTER_COMPONENT, COMPUTE_COMPONENT) class KusuRC(rcplugin.Plugin): def __init__(self): rcplugin.Plugin.__init__(self) self.name = 'cfm-lava' self.desc = 'Setting up cfm for lava' self.ngtypes = ['installer'] self.delete = False global DEBUG if DEBUG: import kusu.util.log as kusulog self.logger = kusulog.getKusuLog() def log(self, msg): try: self.logger.debug(msg) except AttributeError: pass def run(self): global KIT_COMPONENTS associated_ngs, remainder_ngs = self.get_nodegroups(KIT_COMPONENTS) self.remove_dirs(remainder_ngs) if not associated_ngs: self.disable = True # Set up the links and dirs only if the # master component is installed. global MASTER_COMPONENT if self.is_installed(MASTER_COMPONENT): self.setup_dirs_and_symlinks(associated_ngs) self.update_config_files() return True def is_installed(self, component): retcode = self.runCommand('rpm -q %s' % component)[0] return retcode == 0 def chown(self, f, user='root', group='root'): if not isinstance(f, path): f = path(f) if f.exists(): uid = pwd.getpwnam(user)[2] gid = pwd.getpwnam(group)[3] f.chown(uid, gid) else: self.log('Error: file %s does not exist' % f) def update_config_files(self): """ This method covers the corner case where 1. lava-master-component is already installed and configured on the installer AND 2. lava kit is just added to a cross-distro compute nodegroup which has existing nodes. ngedit is used to associate component-lava-compute 3. Either ngedit runs "cfmsync -f -p" or that is done manually on the command line by the user. Without this method, the lsf.cluster.lava config file will not be updated to reflect the existing compute nodes of this cross-distro compute nodegroup. The other lava config files like hosts and lsb.hosts contains all nodes regardless of component-lava-compute associations hence they don't need to be updated. """ lsf_cluster_lava_new = path('/etc/lava/conf/lsf.cluster.lava.new') lsf_cluster_lava = path('/etc/lava/conf/lsf.cluster.lava') cmd = '/opt/kusu/bin/genconfig lavacluster_1_0 > %s' % \ lsf_cluster_lava_new ret, out, err = self.runCommand(cmd) if ret == 0 and lsf_cluster_lava_new.text(): if not lsf_cluster_lava_new.read_md5() == \ lsf_cluster_lava.read_md5(): self.chown(lsf_cluster_lava_new, 'lavaadmin', 'lavaadmin') lsf_cluster_lava_new.chmod(0644) lsf_cluster_lava_new.move(lsf_cluster_lava) # Tell lava to read new configuration # Note: Still require cfmsync -f for compute nodes to # get the updated config file. ret, out, err = self.runCommand('lsadmin reconfig -f') else: self.log('Error running cmd "%s": (%s) %s' % (cmd, ret, err)) if lsf_cluster_lava_new.exists(): lsf_cluster_lava_new.remove() def get_nodegroups(self, kit_components): """ Returns a tuple consisting of two sets of nodegroups 1. nodegroups associated with KIT_COMPONENTS 2. remaining nodegroups, i.e. those that are not associated with KIT_COMPONENTS """ associated_nodegroups = self.dbs.NodeGroups.select( self.dbs.NodeGroups.join_to('components') & self.dbs.Components.c.cname.in_(*kit_components) ) all_nodegroups = self.dbs.NodeGroups.select() return (set(associated_nodegroups), set(all_nodegroups) - set(associated_nodegroups)) def setup_dirs_and_symlinks(self, nodegroups): """ Set up directories and symlinks for nodegroups associated with COMPONENTS. """ for ng in nodegroups: DIRS = ['/etc/cfm/%s/etc/lava/conf/lsbatch/lava/configdir' % ng.ngname] self.make_dirs(DIRS, mode=0755) FILES = ['/etc/lava/conf/hosts', '/etc/lava/conf/lsf.cluster.lava', '/etc/lava/conf/lsf.conf'] self.make_symlinks(FILES, ng.ngname) def make_dirs(self, dirs, mode=0755): for d in dirs: d = path(d) if not d.exists(): self.log('Making directory %s' % d) d.makedirs(mode=mode) def make_symlinks(self, files, ngname): for f in files: source = path(f) dest = path('/etc/cfm/%s%s' % (ngname, f)) if not dest.islink(): self.log('Symlink from %s to %s' % (source, dest)) source.symlink(dest) def remove_dirs(self, nodegroups): """ Remove the symlinks for those nodegroups that are not associated with KIT_COMPONENTS. """ for ng in nodegroups: d = path('/etc/cfm/%s/etc/lava' % ng.ngname) if d.exists(): self.log('Removing directory %s' % d) d.rmtree() d = path('/opt/kusu/cfm/%d/etc/lava' % ng.ngid) if d.exists(): self.log('Removing directory %s' % d) d.rmtree()