diff options
author | Michael DeHaan <mdehaan@redhat.com> | 2009-01-05 14:44:16 -0500 |
---|---|---|
committer | Michael DeHaan <mdehaan@redhat.com> | 2009-01-05 14:44:16 -0500 |
commit | 352bc629bd1f7790e895aceb380dbe315356e835 (patch) | |
tree | 7ca7a2f908abd5fbbdf4e98b6547936e656639bf | |
parent | 6e73337ad583f7dc52fad37aa8fcfe45abbf0842 (diff) | |
download | cobbler-352bc629bd1f7790e895aceb380dbe315356e835.tar.gz cobbler-352bc629bd1f7790e895aceb380dbe315356e835.tar.xz cobbler-352bc629bd1f7790e895aceb380dbe315356e835.zip |
(A) It is unneccessary to run restorecon when the contexts on the directories is already correct.
(B) Modify cobbler check code to suggest directories to set semanage rules on/for.
-rw-r--r-- | cobbler/action_check.py | 26 | ||||
-rw-r--r-- | cobbler/action_litesync.py | 6 | ||||
-rw-r--r-- | cobbler/action_sync.py | 90 | ||||
-rw-r--r-- | cobbler/api.py | 8 | ||||
-rw-r--r-- | cobbler/modules/cli_misc.py | 7 | ||||
-rw-r--r-- | cobbler/pxegen.py | 30 | ||||
-rw-r--r-- | cobbler/utils.py | 97 | ||||
-rw-r--r-- | triggers/restart-services.trigger | 2 |
8 files changed, 175 insertions, 91 deletions
diff --git a/cobbler/action_check.py b/cobbler/action_check.py index 8eeeb41b..1f59da06 100644 --- a/cobbler/action_check.py +++ b/cobbler/action_check.py @@ -147,7 +147,31 @@ class BootCheck: if line.find("httpd_can_network_connect ") != -1: if line.find("off") != -1: status.append(_("Must enable selinux boolean to enable Apache and web services components, run: setsebool -P httpd_can_network_connect true")) - + data3 = sub_process.Popen("/usr/sbin/semanage fcontext -l | grep public_content_t",shell=True,stdout=sub_process.PIPE).communicate()[0] + #print "DEBUG: data3=\n%s\n" % data3 + + rule1 = False + rule2 = False + rule3 = False + selinux_msg = "/usr/sbin/semanage fcontext -a -t public_content_t \"%s\"" + for line in data3.split("\n"): + if line.startswith("/tftpboot/.*") and line.find("public_content_t") != -1: + rule1 = True + if line.startswith("/var/lib/tftpboot/.*") and line.find("public_content_t") != -1: + rule2 = True + if line.startswith("/var/www/cobbler/images/.*") and line.find("public_content_t") != -1: + rule3 = True + + rules = [] + if not os.path.exists("/tftpboot") and not rule1: + rules.append(selinux_msg % "/tftpboot/.*") + else: + if not rule2: + rules.append(selinux_msg % "/var/lib/tftpboot/.*") + if not rule3: + rules.append(selinux_msg % "/var/www/cobbler/images/.*") + if len(rules) > 0: + status.append("you need to set some SELinux content rules to ensure cobbler works correctly in your SELinux environment, run the following: %s" % " && ".join(rules)) def check_for_default_password(self,status): default_pass = self.settings.default_password_crypted diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py index b040db0a..6f239578 100644 --- a/cobbler/action_litesync.py +++ b/cobbler/action_litesync.py @@ -46,11 +46,11 @@ class BootLiteSync: Handles conversion of internal state to the tftpboot tree layout """ - def __init__(self,config): + def __init__(self,config,verbose=True): """ Constructor """ - self.verbose = True + self.verbose = verbose self.config = config self.distros = config.distros() self.profiles = config.profiles() @@ -58,7 +58,7 @@ class BootLiteSync: self.images = config.images() self.settings = config.settings() self.repos = config.repos() - self.sync = config.api.get_sync() + self.sync = config.api.get_sync(verbose) def add_single_distro(self, name): # get the distro record diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index 40e5c443..4b334044 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -56,19 +56,22 @@ class BootSync: """ Constructor """ - self.verbose = verbose - self.config = config - self.api = config.api - self.distros = config.distros() - self.profiles = config.profiles() - self.systems = config.systems() - self.settings = config.settings() - self.repos = config.repos() - self.templar = templar.Templar(config) - self.pxegen = pxegen.PXEGen(config) - self.dns = dns - self.dhcp = dhcp - self.bootloc = utils.tftpboot_location() + self.verbose = verbose + self.config = config + self.api = config.api + self.distros = config.distros() + self.profiles = config.profiles() + self.systems = config.systems() + self.settings = config.settings() + self.repos = config.repos() + self.templar = templar.Templar(config) + self.pxegen = pxegen.PXEGen(config) + self.dns = dns + self.dhcp = dhcp + self.bootloc = utils.tftpboot_location() + self.pxegen.verbose = verbose + self.dns.verbose = verbose + self.dhcp.verbose = verbose def run(self): """ @@ -78,34 +81,65 @@ class BootSync: if not os.path.exists(self.bootloc): raise CX(_("cannot find directory: %s") % self.bootloc) + if self.verbose: + print "- running pre-sync triggers" + # run pre-triggers... utils.run_triggers(None, "/var/lib/cobbler/triggers/sync/pre/*") # (paranoid) in case the pre-trigger modified any objects... + + if self.verbose: + print "- loading configuration" self.api.deserialize() + self.distros = self.config.distros() self.profiles = self.config.profiles() self.systems = self.config.systems() self.settings = self.config.settings() self.repos = self.config.repos() - self.pxegen = pxegen.PXEGen(self.config) # execute the core of the sync operation + + if self.verbose: + print "- cleaning trees" self.clean_trees() + + if self.verbose: + print "- copying bootloaders" self.pxegen.copy_bootloaders() + + if self.verbose: + print "- copying distros" self.pxegen.copy_distros() + + if self.verbose: + print "- copying images" self.pxegen.copy_images() + for x in self.systems: + if self.verbose: + print "- copying files for system: %s" % x.name self.pxegen.write_all_system_files(x) + if self.settings.manage_dhcp: + if self.verbose: + print "- rendering DHCP files" self.dhcp.write_dhcp_file() self.dhcp.regen_ethers() if self.settings.manage_dns: + if self.verbose: + print "- rendering DNS files" self.dns.regen_hosts() self.dns.write_dns_files() + + if self.verbose: + print "- generating PXE menu structure" self.pxegen.make_pxe_menu() # run post-triggers + if self.verbose: + print "- running post-sync triggers" utils.run_triggers(None, "/var/lib/cobbler/triggers/sync/post/*") return True @@ -126,14 +160,14 @@ class BootSync: path = os.path.join(self.settings.webdir,x) if os.path.isfile(path): if not x.endswith(".py"): - utils.rmfile(path) + utils.rmfile(path,verbose=self.verbose) if os.path.isdir(path): if not x in ["web", "webui", "localmirror","repo_mirror","ks_mirror","images","links","repo_profile","repo_system","svc","rendered"] : # delete directories that shouldn't exist - utils.rmtree(path) + utils.rmtree(path,verbose=self.verbose) if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles","repo_profile","repo_system","rendered"]: # clean out directory contents - utils.rmtree_contents(path) + utils.rmtree_contents(path,verbose=self.verbose) pxelinux_dir = os.path.join(self.bootloc, "pxelinux.cfg") images_dir = os.path.join(self.bootloc, "images") yaboot_bin_dir = os.path.join(self.bootloc, "ppc") @@ -141,21 +175,21 @@ class BootSync: s390_dir = os.path.join(self.bootloc, "s390x") rendered_dir = os.path.join(self.settings.webdir, "rendered") if not os.path.exists(pxelinux_dir): - utils.mkdir(pxelinux_dir) + utils.mkdir(pxelinux_dir,verbose=self.verbose) if not os.path.exists(images_dir): - utils.mkdir(images_dir) + utils.mkdir(images_dir,verbose=self.verbose) if not os.path.exists(rendered_dir): - utils.mkdir(rendered_dir) + utils.mkdir(rendered_dir,verbose=self.verbose) if not os.path.exists(yaboot_bin_dir): - utils.mkdir(yaboot_bin_dir) + utils.mkdir(yaboot_bin_dir,verbose=self.verbose) if not os.path.exists(yaboot_cfg_dir): - utils.mkdir(yaboot_cfg_dir) - utils.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg")) - utils.rmtree_contents(os.path.join(self.bootloc, "images")) - utils.rmtree_contents(os.path.join(self.bootloc, "s390x")) - utils.rmtree_contents(os.path.join(self.bootloc, "ppc")) - utils.rmtree_contents(os.path.join(self.bootloc, "etc")) - utils.rmtree_contents(rendered_dir) + utils.mkdir(yaboot_cfg_dir,verbose=self.verbose) + utils.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg"),verbose=self.verbose) + utils.rmtree_contents(os.path.join(self.bootloc, "images"),verbose=self.verbose) + utils.rmtree_contents(os.path.join(self.bootloc, "s390x"),verbose=self.verbose) + utils.rmtree_contents(os.path.join(self.bootloc, "ppc"),verbose=self.verbose) + utils.rmtree_contents(os.path.join(self.bootloc, "etc"),verbose=self.verbose) + utils.rmtree_contents(rendered_dir,verbose=self.verbose) diff --git a/cobbler/api.py b/cobbler/api.py index 84c2c638..f4178239 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -511,7 +511,7 @@ class BootAPI: validator = action_validate.Validate(self._config) return validator.run() - def sync(self): + def sync(self,verbose=False): """ Take the values currently written to the configuration files in /etc, and /var, and build out the information tree found in @@ -519,10 +519,10 @@ class BootAPI: saved with serialize() will NOT be synchronized with this command. """ self.log("sync") - sync = self.get_sync() + sync = self.get_sync(verbose=verbose) return sync.run() - def get_sync(self): + def get_sync(self,verbose=False): self.dhcp = self.get_module_from_file( "dhcp", "module", @@ -533,7 +533,7 @@ class BootAPI: "module", "manage_bind" ).get_manager(self._config) - return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns) + return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns,verbose=verbose) def reposync(self, name=None, tries=1, nofail=False): """ diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py index 94ccc0d1..14e61ff5 100644 --- a/cobbler/modules/cli_misc.py +++ b/cobbler/modules/cli_misc.py @@ -172,7 +172,10 @@ class StatusFunction(commands.CobblerFunction): ######################################################## class SyncFunction(commands.CobblerFunction): - + + def add_options(self, p, args): + p.add_option("--verbose", dest="verbose", action="store_true", help="run sync with more output") + def help_me(self): return HELP_FORMAT % ("cobbler sync","") @@ -180,7 +183,7 @@ class SyncFunction(commands.CobblerFunction): return "sync" def run(self): - return self.api.sync() + return self.api.sync(verbose=self.options.verbose) ######################################################## diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py index 73d56933..e0172549 100644 --- a/cobbler/pxegen.py +++ b/cobbler/pxegen.py @@ -62,6 +62,7 @@ class PXEGen: self.images = config.images() self.templar = templar.Templar(config) self.bootloc = utils.tftpboot_location() + self.verbose = False def copy_bootloaders(self): """ @@ -73,27 +74,27 @@ class PXEGen: # copy syslinux from one of two locations try: - utils.copyfile_pattern('/usr/lib/syslinux/pxelinux.0', dst, api=self.api) + utils.copyfile_pattern('/usr/lib/syslinux/pxelinux.0', dst, api=self.api, verbose=self.verbose) except: - utils.copyfile_pattern('/usr/share/syslinux/pxelinux.0', dst, api=self.api) + utils.copyfile_pattern('/usr/share/syslinux/pxelinux.0', dst, api=self.api, verbose=self.verbose) # copy memtest only if we find it - utils.copyfile_pattern('/boot/memtest*', dst, require_match=False, api=self.api) + utils.copyfile_pattern('/boot/memtest*', dst, require_match=False, api=self.api, verbose=self.verbose) # copy elilo which we include for IA64 targets - utils.copyfile_pattern('/var/lib/cobbler/elilo-3.8-ia64.efi', dst, api=self.api) + utils.copyfile_pattern('/var/lib/cobbler/elilo-3.8-ia64.efi', dst, api=self.api, verbose=self.verbose) # copy menu.c32 as the older one has some bugs on certain RHEL - utils.copyfile_pattern('/var/lib/cobbler/menu.c32', dst, api=self.api) + utils.copyfile_pattern('/var/lib/cobbler/menu.c32', dst, api=self.api, verbose=self.verbose) # copy yaboot which we include for PowerPC targets - utils.copyfile_pattern('/var/lib/cobbler/yaboot-1.3.14', dst, api=self.api) + utils.copyfile_pattern('/var/lib/cobbler/yaboot-1.3.14', dst, api=self.api, verbose=self.verbose) # copy memdisk as we need it to boot ISOs try: - utils.copyfile_pattern('/usr/lib/syslinux/memdisk', dst, api=self.api) + utils.copyfile_pattern('/usr/lib/syslinux/memdisk', dst, api=self.api, verbose=self.verbose) except: - utils.copyfile_pattern('/usr/share/syslinux/memdisk', dst, api=self.api) + utils.copyfile_pattern('/usr/share/syslinux/memdisk', dst, api=self.api, verbose=self.verbose) def copy_distros(self): @@ -109,6 +110,8 @@ class PXEGen: errors = list() for d in self.distros: try: + if self.verbose: + print "- copying files for distro: %s" % d.name self.copy_single_distro_files(d) except CX, e: errors.append(e) @@ -125,6 +128,8 @@ class PXEGen: errors = list() for i in self.images: try: + if self.verbose: + print "- copying files for image: %s" % i.name self.copy_single_image_files(i) except CX, e: errors.append(e) @@ -152,9 +157,9 @@ class PXEGen: allow_symlink=True dst1 = os.path.join(distro_dir, b_kernel) dst2 = os.path.join(distro_dir, b_initrd) - utils.linkfile(kernel, dst1, symlink_ok=allow_symlink, api=self.api) + utils.linkfile(kernel, dst1, symlink_ok=allow_symlink, api=self.api, verbose=self.verbose) - utils.linkfile(initrd, dst2, symlink_ok=allow_symlink, api=self.api) + utils.linkfile(initrd, dst2, symlink_ok=allow_symlink, api=self.api, verbose=self.verbose) def copy_single_image_files(self, img): images_dir = os.path.join(self.bootloc, "images2") @@ -166,7 +171,7 @@ class PXEGen: os.makedirs(images_dir) basename = os.path.basename(img.file) newfile = os.path.join(images_dir, img.name) - utils.linkfile(filename, newfile, api=self.api) + utils.linkfile(filename, newfile, api=self.api, verbose=self.verbose) return True def write_all_system_files(self,system): @@ -240,7 +245,8 @@ class PXEGen: utils.rmfile(f2) def make_pxe_menu(self): - self.make_s390_pseudo_pxe_menu() + # FIXME: not used for now, future feature? + # self.make_s390_pseudo_pxe_menu() self.make_actual_pxe_menu() def make_s390_pseudo_pxe_menu(self): diff --git a/cobbler/utils.py b/cobbler/utils.py index fece9476..e5b3db6a 100644 --- a/cobbler/utils.py +++ b/cobbler/utils.py @@ -822,7 +822,7 @@ def is_safe_to_hardlink(src,dst,api): # we're dealing with SELinux and files that are not safe to chcon return False -def linkfile(src, dst, symlink_ok=False, api=None): +def linkfile(src, dst, symlink_ok=False, api=None, verbose=False): """ Attempt to create a link dst that points to src. Because file systems suck we attempt several different methods or bail to @@ -843,25 +843,30 @@ def linkfile(src, dst, symlink_ok=False, api=None): if not is_safe_to_hardlink(src,dst,api): # may have to remove old hardlinks for SELinux reasons # as previous implementations were not complete - os.remove(dst) + if verbose: + print "- removing: %s" % dst + os.remove(dst) else: - restorecon(dst,api=api) + # restorecon(dst,api=api,verbose=verbose) return True elif os.path.islink(dst): # existing path exists and is a symlink, update the symlink + if verbose: + print "- removing: %s" % dst os.remove(dst) if is_safe_to_hardlink(src,dst,api): # we can try a hardlink if the destination isn't to NFS or Samba # this will help save space and sync time. try: + if verbose: + print "- trying hardlink %s -> %s" % (src,dst) rc = os.link(src, dst) - restorecon(dst,api=api) + # restorecon(dst,api=api,verbose=verbose) return rc except (IOError, OSError): # hardlink across devices, or link already exists - # can result in extra call to restorecon but no - # major harm, we'll just symlink it if we can + # we'll just symlink it if we can # or otherwise copy it pass @@ -869,20 +874,24 @@ def linkfile(src, dst, symlink_ok=False, api=None): # we can symlink anywhere except for /tftpboot because # that is run chroot, so if we can symlink now, try it. try: + if verbose: + print "- trying symlink %s -> %s" % (src,dst) rc = os.symlink(src, dst) - restorecon(dst,api=api) + # restorecon(dst,api=api,verbose=verbose) return rc except (IOError, OSError): pass # we couldn't hardlink and we couldn't symlink so we must copy - return copyfile(src, dst, api=api) + return copyfile(src, dst, api=api, verbose=verbose) -def copyfile(src,dst,api=None): +def copyfile(src,dst,api=None,verbose=False): try: + if verbose: + print "- copying: %s -> %s" % (src,dst) rc = shutil.copyfile(src,dst) - restorecon(dst,api) + # restorecon(dst,api,verbose=verbose) return rc except: if not os.access(src,os.R_OK): @@ -894,40 +903,44 @@ def copyfile(src,dst,api=None): # traceback.print_exc() # raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst}) -def copyfile_pattern(pattern,dst,require_match=True,symlink_ok=False,api=None): +def copyfile_pattern(pattern,dst,require_match=True,symlink_ok=False,api=None, verbose=False): files = glob.glob(pattern) if require_match and not len(files) > 0: raise CX(_("Could not find files matching %s") % pattern) for file in files: base = os.path.basename(file) dst1 = os.path.join(dst,os.path.basename(file)) - linkfile(file,dst1,symlink_ok=symlink_ok,api=api) - restorecon(dst1,api=api) + linkfile(file,dst1,symlink_ok=symlink_ok,api=api,verbose=verbose) + # restorecon(dst1,api=api,verbose=verbose) -def restorecon(dest, api): - - """ - Wrapper around functions to manage SELinux contexts. - Use chcon public_content_t where we can to allow - hardlinking between /var/www and tftpboot but use - restorecon everywhere else. - """ - - if not api.is_selinux_enabled(): - return True - - tdest = os.path.realpath(dest) - # remoted = is_remote_file(tdest) - - cmd = [ "/sbin/restorecon",dest ] - rc = sub_process.call(cmd,shell=False,close_fds=True) - if rc != 0: - raise CX("restorecon operation failed: %s" % cmd) - - return 0 +#def restorecon(dest, api, verbose=False): +# +# """ +# Wrapper around functions to manage SELinux contexts. +# Use chcon public_content_t where we can to allow +# hardlinking between /var/www and tftpboot but use +# restorecon everywhere else. +# """ +# +# if not api.is_selinux_enabled(): +# return True +# +# tdest = os.path.realpath(dest) +# # remoted = is_remote_file(tdest) +# +# cmd = [ "/sbin/restorecon",dest ] +# if verbose: +# print "- %s" % " ".join(cmd) +# rc = sub_process.call(cmd,shell=False,close_fds=True) +# if rc != 0: +# raise CX("restorecon operation failed: %s" % cmd) +# +# return 0 -def rmfile(path): +def rmfile(path,verbose=False): try: + if verbose: + print "- removing: %s" % path os.unlink(path) return True except OSError, ioe: @@ -936,16 +949,18 @@ def rmfile(path): raise CX(_("Error deleting %s") % path) return True -def rmtree_contents(path): +def rmtree_contents(path,verbose=False): what_to_delete = glob.glob("%s/*" % path) for x in what_to_delete: - rmtree(x) + rmtree(x,verbose=verbose) -def rmtree(path): +def rmtree(path,verbose=False): try: if os.path.isfile(path): - return rmfile(path) + return rmfile(path,verbose=verbose) else: + if verbose: + print "- removing: %s" % path return shutil.rmtree(path,ignore_errors=True) except OSError, ioe: traceback.print_exc() @@ -953,8 +968,10 @@ def rmtree(path): raise CX(_("Error deleting %s") % path) return True -def mkdir(path,mode=0777): +def mkdir(path,mode=0777,verbose=False): try: + if verbose: + "- mkdir: %s" % path return os.makedirs(path,mode) except OSError, oe: if not oe.errno == 17: # already exists (no constant for 17?) diff --git a/triggers/restart-services.trigger b/triggers/restart-services.trigger index 5f77b4d8..82dc0427 100644 --- a/triggers/restart-services.trigger +++ b/triggers/restart-services.trigger @@ -14,7 +14,7 @@ omapi_enabled = settings.omapi_enabled omapi_port = settings.omapi_port # load up our DHCP and DNS modules -bootapi.get_sync() +bootapi.get_sync(verbose=False) # bootapi.dhcp and bootapi.dns are now module references # special handling as we don't want to restart it twice |