Source code for cobbler.api

from past.builtins import cmp
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import object
from configparser import ConfigParser

import os
import random
import tempfile

from cobbler.actions import status, dlcontent, hardlink, sync, buildiso, replicate, report, log, acl, check, reposync
from cobbler import autoinstall_manager
from cobbler import clogger
from cobbler.cobbler_collections import manager
from cobbler.items import package, system, image, profile, repo, mgmtclass, distro, file
from cobbler import module_loader
from cobbler import power_manager
from cobbler import tftpgen
from cobbler import utils
from cobbler import yumgen
from cobbler import autoinstallgen
from cobbler import download_manager
from cobbler.cexceptions import CX
from cobbler.utils import _


ERROR = 100
INFO = 10
DEBUG = 5

# FIXME: add --quiet depending on if not --verbose?
RSYNC_CMD = "rsync -a %s '%s' %s --progress"

# notes on locking:
# CobblerAPI is a singleton object
# the XMLRPC variants allow 1 simultaneous request
# therefore we flock on /etc/cobbler/settings for now
# on a request by request basis.


[docs]class CobblerAPI(object): """ Python API module for Cobbler. See source for cobbler.py, or pydoc, for example usage. Cli apps and daemons should import api.py, and no other cobbler code. """ __shared_state = {} __has_loaded = False def __init__(self, is_cobblerd=False): """ Constructor """ # FIXME: this should be switchable through some simple system self.__dict__ = CobblerAPI.__shared_state self.perms_ok = False if not CobblerAPI.__has_loaded: # NOTE: we do not log all API actions, because # a simple CLI invocation may call adds and such # to load the config, which would just fill up # the logs, so we'll do that logging at CLI # level (and remote.py web service level) instead. random.seed() self.is_cobblerd = is_cobblerd try: self.logger = clogger.Logger() except CX: # return to CLI/other but perms are not valid # perms_ok is False return # FIXME: conslidate into 1 server instance self.selinux_enabled = utils.is_selinux_enabled() self.dist, self.os_version = utils.os_release() CobblerAPI.__has_loaded = True # load the modules first, or nothing else works... module_loader.load_modules() self._collection_mgr = manager.CollectionManager(self) self.deserialize() # import signatures try: utils.load_signatures(self.settings().signature_path) except Exception as e: self.log("Failed to load signatures from %s: %s" % (self.settings().signature_path, e)) return self.log("%d breeds and %d OS versions read from the signature file" % ( len(utils.get_valid_breeds()), len(utils.get_valid_os_versions())) ) self.authn = self.get_module_from_file( "authentication", "module", "authn_configfile" ) self.authz = self.get_module_from_file( "authorization", "module", "authz_allowall" ) # FIXME: pass more loggers around, and also see that those # using things via tasks construct their own yumgen/tftpgen # versus reusing this one, which has the wrong logger # (most likely) for background tasks. self.autoinstallgen = autoinstallgen.AutoInstallationGen(self._collection_mgr) self.yumgen = yumgen.YumGen(self._collection_mgr) self.tftpgen = tftpgen.TFTPGen(self._collection_mgr, logger=self.logger) self.power_mgr = power_manager.PowerManager(self, self._collection_mgr) self.logger.debug("API handle initialized") self.perms_ok = True # ==========================================================
[docs] def is_selinux_enabled(self): """ Returns whether selinux is enabled on the cobbler server. We check this just once at cobbler API init time, because a restart is required to change this; this does /not/ check enforce/permissive, nor does it need to. """ return self.selinux_enabled
[docs] def is_selinux_supported(self): """ Returns whether or not the OS is sufficient enough to run with SELinux enabled (currently EL 5 or later). """ # FIXME: This detection is flawed. There is more than just Rhel with selinux and the original implemenation was # too broad. if ("red hat" in self.dist or "redhat" in self.dist) and self.os_version >= 5: return True # doesn't support public_content_t return False
# ==========================================================
[docs] def last_modified_time(self): """ Returns the time of the last modification to cobbler, made by any API instance, regardless of the serializer type. """ if not os.path.exists("/var/lib/cobbler/.mtime"): fd = open("/var/lib/cobbler/.mtime", 'w') fd.write("0") fd.close() return float(0) fd = open("/var/lib/cobbler/.mtime", 'r') data = fd.read().strip() return float(data)
# ==========================================================
[docs] def log(self, msg, args=None, debug=False): if debug: logger = self.logger.debug else: logger = self.logger.info if args is None: logger("%s" % msg) else: logger("%s; %s" % (msg, str(args)))
# ==========================================================
[docs] def version(self, extended=False): """ What version is cobbler? If extended == False, returns a float for backwards compatibility If extended == True, returns a dict: gitstamp -- the last git commit hash gitdate -- the last git commit date on the builder machine builddate -- the time of the build version -- something like "1.3.2" version_tuple -- something like [ 1, 3, 2 ] """ config = ConfigParser() config.read("/etc/cobbler/version") data = {} data["gitdate"] = config.get("cobbler", "gitdate") data["gitstamp"] = config.get("cobbler", "gitstamp") data["builddate"] = config.get("cobbler", "builddate") data["version"] = config.get("cobbler", "version") # dont actually read the version_tuple from the version file data["version_tuple"] = [] for num in data["version"].split("."): data["version_tuple"].append(int(num)) if not extended: # for backwards compatibility and use with koan's comparisons elems = data["version_tuple"] return int(elems[0]) + 0.1 * int(elems[1]) + 0.001 * int(elems[2]) else: return data
# ========================================================== def __cmp(self, a, b): return cmp(a.name, b.name)
[docs] def get_item(self, what, name): self.log("get_item", [what, name], debug=True) item = self._collection_mgr.get_items(what).get(name) self.log("done with get_item", [what, name], debug=True) return item # self._collection_mgr.get_items(what).get(name)
[docs] def get_items(self, what): self.log("get_items", [what], debug=True) items = self._collection_mgr.get_items(what) self.log("done with get_items", [what], debug=True) return items # self._collection_mgr.get_items(what)
[docs] def distros(self): """ Return the current list of distributions """ return self.get_items("distro")
[docs] def profiles(self): """ Return the current list of profiles """ return self.get_items("profile")
[docs] def systems(self): """ Return the current list of systems """ return self.get_items("system")
[docs] def repos(self): """ Return the current list of repos """ return self.get_items("repo")
[docs] def images(self): """ Return the current list of images """ return self.get_items("image")
[docs] def settings(self): """ Return the application configuration """ return self._collection_mgr.settings()
[docs] def mgmtclasses(self): """ Return the current list of mgmtclasses """ return self.get_items("mgmtclass")
[docs] def packages(self): """ Return the current list of packages """ return self.get_items("package")
[docs] def files(self): """ Return the current list of files """ return self.get_items("file")
# =======================================================================
[docs] def copy_item(self, what, ref, newname, logger=None): self.log("copy_item(%s)" % what, [ref.name, newname]) self.get_items(what).copy(ref, newname, logger=logger)
[docs] def copy_distro(self, ref, newname): self.copy_item("distro", ref, newname, logger=None)
[docs] def copy_profile(self, ref, newname): self.copy_item("profile", ref, newname, logger=None)
[docs] def copy_system(self, ref, newname): self.copy_item("system", ref, newname, logger=None)
[docs] def copy_repo(self, ref, newname): self.copy_item("repo", ref, newname, logger=None)
[docs] def copy_image(self, ref, newname): self.copy_item("image", ref, newname, logger=None)
[docs] def copy_mgmtclass(self, ref, newname): self.copy_item("mgmtclass", ref, newname, logger=None)
[docs] def copy_package(self, ref, newname): self.copy_item("package", ref, newname, logger=None)
[docs] def copy_file(self, ref, newname): self.copy_item("file", ref, newname, logger=None)
# ==========================================================================
[docs] def remove_item(self, what, ref, recursive=False, delete=True, with_triggers=True, logger=None): if isinstance(what, str): if isinstance(ref, str): ref = self.get_item(what, ref) if ref is None: return # nothing to remove self.log("remove_item(%s)" % what, [ref.name]) self.get_items(what).remove(ref.name, recursive=recursive, with_delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_distro(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("distro", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_profile(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("profile", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_system(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("system", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_repo(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("repo", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_image(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("image", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_mgmtclass(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("mgmtclass", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_package(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("package", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
[docs] def remove_file(self, ref, recursive=False, delete=True, with_triggers=True, logger=None): self.remove_item("file", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
# ==========================================================================
[docs] def rename_item(self, what, ref, newname, logger=None): self.log("rename_item(%s)" % what, [ref.name, newname]) self.get_items(what).rename(ref, newname, logger=logger)
[docs] def rename_distro(self, ref, newname, logger=None): self.rename_item("distro", ref, newname, logger=logger)
[docs] def rename_profile(self, ref, newname, logger=None): self.rename_item("profile", ref, newname, logger=logger)
[docs] def rename_system(self, ref, newname, logger=None): self.rename_item("system", ref, newname, logger=logger)
[docs] def rename_repo(self, ref, newname, logger=None): self.rename_item("repo", ref, newname, logger=logger)
[docs] def rename_image(self, ref, newname, logger=None): self.rename_item("image", ref, newname, logger=logger)
[docs] def rename_mgmtclass(self, ref, newname, logger=None): self.rename_item("mgmtclass", ref, newname, logger=logger)
[docs] def rename_package(self, ref, newname, logger=None): self.rename_item("package", ref, newname, logger=logger)
[docs] def rename_file(self, ref, newname, logger=None): self.rename_item("file", ref, newname, logger=logger)
# ========================================================================== # FIXME: add a new_item method
[docs] def new_distro(self, is_subobject=False): self.log("new_distro", [is_subobject]) return distro.Distro(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_profile(self, is_subobject=False): self.log("new_profile", [is_subobject]) return profile.Profile(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_system(self, is_subobject=False): self.log("new_system", [is_subobject]) return system.System(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_repo(self, is_subobject=False): self.log("new_repo", [is_subobject]) return repo.Repo(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_image(self, is_subobject=False): self.log("new_image", [is_subobject]) return image.Image(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_mgmtclass(self, is_subobject=False): self.log("new_mgmtclass", [is_subobject]) return mgmtclass.Mgmtclass(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_package(self, is_subobject=False): self.log("new_package", [is_subobject]) return package.Package(self._collection_mgr, is_subobject=is_subobject)
[docs] def new_file(self, is_subobject=False): self.log("new_file", [is_subobject]) return file.File(self._collection_mgr, is_subobject=is_subobject)
# ==========================================================================
[docs] def add_item(self, what, ref, check_for_duplicate_names=False, save=True, logger=None): self.log("add_item(%s)" % what, [ref.name]) self.get_items(what).add(ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_distro(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("distro", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_profile(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("profile", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_system(self, ref, check_for_duplicate_names=False, check_for_duplicate_netinfo=False, save=True, logger=None): self.add_item("system", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_repo(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("repo", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_image(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("image", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_mgmtclass(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("mgmtclass", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_package(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("package", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
[docs] def add_file(self, ref, check_for_duplicate_names=False, save=True, logger=None): self.add_item("file", ref, check_for_duplicate_names=check_for_duplicate_names, save=save, logger=logger)
# ========================================================================== # FIXME: find_items should take all the arguments the other find # methods do.
[docs] def find_items(self, what, criteria=None): self.log("find_items", [what]) # defaults if criteria is None: criteria = {} items = self._collection_mgr.get_items(what) # empty criteria returns everything if criteria == {}: res = items else: res = items.find(return_list=True, no_errors=False, **criteria) return res
[docs] def find_distro(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.distros().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_profile(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.profiles().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_system(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.systems().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_repo(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.repos().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_image(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.images().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_mgmtclass(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.mgmtclasses().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_package(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.packages().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
[docs] def find_file(self, name=None, return_list=False, no_errors=False, **kargs): return self._collection_mgr.files().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
# ========================================================================== def __since(self, mtime, collector, collapse=False): """ Called by get_*_since functions. """ results1 = collector() results2 = [] for x in results1: if x.mtime == 0 or x.mtime >= mtime: if not collapse: results2.append(x) else: results2.append(x.to_dict()) return results2
[docs] def get_distros_since(self, mtime, collapse=False): """ Returns distros modified since a certain time (in seconds since Epoch) collapse=True specifies returning a dict instead of objects. """ return self.__since(mtime, self.distros, collapse=collapse)
[docs] def get_profiles_since(self, mtime, collapse=False): return self.__since(mtime, self.profiles, collapse=collapse)
[docs] def get_systems_since(self, mtime, collapse=False): return self.__since(mtime, self.systems, collapse=collapse)
[docs] def get_repos_since(self, mtime, collapse=False): return self.__since(mtime, self.repos, collapse=collapse)
[docs] def get_images_since(self, mtime, collapse=False): return self.__since(mtime, self.images, collapse=collapse)
[docs] def get_mgmtclasses_since(self, mtime, collapse=False): return self.__since(mtime, self.mgmtclasses, collapse=collapse)
[docs] def get_packages_since(self, mtime, collapse=False): return self.__since(mtime, self.packages, collapse=collapse)
[docs] def get_files_since(self, mtime, collapse=False): return self.__since(mtime, self.files, collapse=collapse)
# ==========================================================================
[docs] def get_signatures(self): return utils.SIGNATURE_CACHE
[docs] def signature_update(self, logger): try: url = self.settings().signature_url dlmgr = download_manager.DownloadManager(self._collection_mgr, self.logger) # write temp json file tmpfile = tempfile.NamedTemporaryFile() sigjson = dlmgr.urlread(url) tmpfile.write(sigjson.text.encode()) tmpfile.flush() logger.debug("Successfully got file from %s" % self.settings().signature_url) # test the import without caching it try: utils.load_signatures(tmpfile.name, cache=False) except: logger.error("Downloaded signatures failed test load (tempfile = %s)" % tmpfile.name) # rewrite the real signature file and import it for real f = open(self.settings().signature_path, "w") f.write(sigjson.text) f.close() utils.load_signatures(self.settings().signature_path) except: utils.log_exc(logger)
# ==========================================================================
[docs] def dump_vars(self, obj, format=False): return obj.dump_vars(format)
# ==========================================================================
[docs] def auto_add_repos(self): """ Import any repos this server knows about and mirror them. Credit: Seth Vidal. """ self.log("auto_add_repos") try: import yum except: raise CX(_("yum is not installed")) version = yum.__version__ (a, b, c) = version.split(".") version = a * 1000 + b * 100 + c if version < 324: raise CX(_("need yum > 3.2.4 to proceed")) base = yum.YumBase() base.doRepoSetup() repositorys = base.repos.listEnabled() if len(repositorys) == 0: raise CX(_("no repos enabled/available -- giving up.")) for repository in repositorys: url = repository.urls[0] cobbler_repo = self.new_repo() auto_name = repository.name.replace(" ", "") # FIXME: probably doesn't work for yum-rhn-plugin ATM cobbler_repo.set_mirror(url) cobbler_repo.set_name(auto_name) print("auto adding: %s (%s)" % (auto_name, url)) self._collection_mgr.repos().add(cobbler_repo, save=True)
# run cobbler reposync to apply changes # ==========================================================================
[docs] def get_repo_config_for_profile(self, obj): return self.yumgen.get_yum_config(obj, True)
[docs] def get_repo_config_for_system(self, obj): return self.yumgen.get_yum_config(obj, False)
# ==========================================================================
[docs] def get_template_file_for_profile(self, obj, path): template_results = self.tftpgen.write_templates(obj, False, path) if path in template_results: return template_results[path] else: return "# template path not found for specified profile"
[docs] def get_template_file_for_system(self, obj, path): template_results = self.tftpgen.write_templates(obj, False, path) if path in template_results: return template_results[path] else: return "# template path not found for specified system"
# ==========================================================================
[docs] def generate_gpxe(self, profile, system): self.log("generate_gpxe") if system: return self.tftpgen.generate_gpxe("system", system) else: return self.tftpgen.generate_gpxe("profile", profile)
# ==========================================================================
[docs] def generate_bootcfg(self, profile, system): self.log("generate_bootcfg") if system: return self.tftpgen.generate_bootcfg("system", system) else: return self.tftpgen.generate_bootcfg("profile", profile)
# ==========================================================================
[docs] def generate_script(self, profile, system, name): self.log("generate_script") if system: return self.tftpgen.generate_script("system", system, name) else: return self.tftpgen.generate_script("profile", profile, name)
# ==========================================================================
[docs] def check(self, logger=None): """ See if all preqs for network booting are valid. This returns a list of strings containing instructions on things to correct. An empty list means there is nothing to correct, but that still doesn't mean there are configuration errors. This is mainly useful for human admins, who may, for instance, forget to properly set up their TFTP servers for PXE, etc. """ self.log("check") action_check = check.CobblerCheck(self._collection_mgr, logger=logger) return action_check.run()
# ==========================================================================
[docs] def dlcontent(self, force=False, logger=None): """ Downloads bootloader content that may not be avialable in packages for the given arch, ex: if installing on PPC, get syslinux. If installing on x86_64, get elilo, etc. """ # FIXME: teach code that copies it to grab from the right place self.log("dlcontent") grabber = dlcontent.ContentDownloader(self._collection_mgr, logger=logger) return grabber.run(force)
# ==========================================================================
[docs] def validate_autoinstall_files(self, logger=None): self.log("validate_autoinstall_files") autoinstall_mgr = autoinstall_manager.AutoInstallationManager(self._collection_mgr) autoinstall_mgr.validate_autoinstall_files(logger)
# ==========================================================================
[docs] def sync(self, verbose=False, logger=None): """ Take the values currently written to the configuration files in /etc, and /var, and build out the information tree found in /tftpboot. Any operations done in the API that have not been saved with serialize() will NOT be synchronized with this command. """ self.log("sync") sync = self.get_sync(verbose=verbose, logger=logger) sync.run()
# ==========================================================================
[docs] def sync_dhcp(self, verbose=False, logger=None): """ Only build out the DHCP configuration """ self.log("sync_dhcp") sync = self.get_sync(verbose=verbose, logger=logger) sync.sync_dhcp()
# ==========================================================================
[docs] def get_sync(self, verbose=False, logger=None): self.dhcp = self.get_module_from_file( "dhcp", "module", "managers.isc" ).get_manager(self._collection_mgr, logger) self.dns = self.get_module_from_file( "dns", "module", "managers.bind" ).get_manager(self._collection_mgr, logger) self.tftpd = self.get_module_from_file( "tftpd", "module", "managers.in_tftpd", ).get_manager(self._collection_mgr, logger) return sync.CobblerSync(self._collection_mgr, dhcp=self.dhcp, dns=self.dns, tftpd=self.tftpd, verbose=verbose, logger=logger)
# ==========================================================================
[docs] def reposync(self, name=None, tries=1, nofail=False, logger=None): """ Take the contents of /var/lib/cobbler/repos and update them -- or create the initial copy if no contents exist yet. """ self.log("reposync", [name]) action_reposync = reposync.RepoSync(self._collection_mgr, tries=tries, nofail=nofail, logger=logger) action_reposync.run(name)
# ==========================================================================
[docs] def status(self, mode, logger=None): statusifier = status.CobblerStatusReport(self._collection_mgr, mode, logger=logger) return statusifier.run()
# ==========================================================================
[docs] def import_tree(self, mirror_url, mirror_name, network_root=None, autoinstall_file=None, rsync_flags=None, arch=None, breed=None, os_version=None, logger=None): """ Automatically import a directory tree full of distribution files. mirror_url can be a string that represents a path, a user@host syntax for SSH, or an rsync:// address. If mirror_url is a filesystem path and mirroring is not desired, set network_root to something like "nfs://path/to/mirror_url/root" """ self.log("import_tree", [mirror_url, mirror_name, network_root, autoinstall_file, rsync_flags]) # both --path and --name are required arguments if mirror_url is None or not mirror_url: self.log("import failed. no --path specified") return False if mirror_name is None or not mirror_name: self.log("import failed. no --name specified") return False path = os.path.normpath("%s/distro_mirror/%s" % (self.settings().webdir, mirror_name)) if arch is not None: arch = arch.lower() if arch == "x86": # be consistent arch = "i386" if path.split("-")[-1] != arch: path += ("-%s" % arch) # we need to mirror (copy) the files self.log("importing from a network location, running rsync to fetch the files first") utils.mkdir(path) # prevent rsync from creating the directory name twice # if we are copying via rsync if not mirror_url.endswith("/"): mirror_url = "%s/" % mirror_url if mirror_url.startswith("http://") or mirror_url.startswith("https://") or mirror_url.startswith("ftp://") or mirror_url.startswith("nfs://"): # http mirrors are kind of primative. rsync is better. # that's why this isn't documented in the manpage and we don't support them. # TODO: how about adding recursive FTP as an option? self.log("unsupported protocol") return False else: # good, we're going to use rsync.. # we don't use SSH for public mirrors and local files. # presence of user@host syntax means use SSH spacer = "" if not mirror_url.startswith("rsync://") and not mirror_url.startswith("/"): spacer = ' -e "ssh" ' rsync_cmd = RSYNC_CMD if rsync_flags: rsync_cmd += " " + rsync_flags # if --available-as was specified, limit the files we # pull down via rsync to just those that are critical # to detecting what the distro is if network_root is not None: rsync_cmd += " --include-from=/etc/cobbler/import_rsync_whitelist" # kick off the rsync now utils.run_this(rsync_cmd, (spacer, mirror_url, path), self.logger) if network_root is not None: # in addition to mirroring, we're going to assume the path is available # over http, ftp, and nfs, perhaps on an external filer. scanning still requires # --mirror is a filesystem path, but --available-as marks the network path. # this allows users to point the path at a directory containing just the network # boot files while the rest of the distro files are available somewhere else. # find the filesystem part of the path, after the server bits, as each distro # URL needs to be calculated relative to this. if not network_root.endswith("/"): network_root += "/" valid_roots = ["nfs://", "ftp://", "http://", "https://"] for valid_root in valid_roots: if network_root.startswith(valid_root): break else: self.log("Network root given to --available-as must be nfs://, ftp://, http://, or https://") return False if network_root.startswith("nfs://"): try: (a, b, rest) = network_root.split(":", 3) except: self.log("Network root given to --available-as is missing a colon, please see the manpage example.") return False import_module = self.get_module_by_name("managers.import_signatures").get_import_manager(self._collection_mgr, logger) import_module.run(path, mirror_name, network_root, autoinstall_file, arch, breed, os_version)
# ==========================================================================
[docs] def acl_config(self, adduser=None, addgroup=None, removeuser=None, removegroup=None, logger=None): """ Configures users/groups to run the cobbler CLI as non-root. Pass in only one option at a time. Powers "cobbler aclconfig" """ action_acl = acl.AclConfig(self._collection_mgr, logger) action_acl.run( adduser=adduser, addgroup=addgroup, removeuser=removeuser, removegroup=removegroup )
# ==========================================================================
[docs] def serialize(self): """ Save the cobbler_collections to disk. Cobbler internal use only. """ self._collection_mgr.serialize()
[docs] def deserialize(self): """ Load cobbler_collections from disk. Cobbler internal use only. """ return self._collection_mgr.deserialize()
# ==========================================================================
[docs] def get_module_by_name(self, module_name): """ Returns a loaded cobbler module named 'name', if one exists, else None. Cobbler internal use only. """ return module_loader.get_module_by_name(module_name)
[docs] def get_module_from_file(self, section, name, fallback=None): """ Looks in /etc/cobbler/modules.conf for a section called 'section' and a key called 'name', and then returns the module that corresponds to the value of that key. Cobbler internal use only. """ return module_loader.get_module_from_file(section, name, fallback)
[docs] def get_module_name_from_file(self, section, name, fallback=None): """ Looks up a module the same as get_module_from_file but returns the module name rather than the module itself """ return module_loader.get_module_name(section, name, fallback)
[docs] def get_modules_in_category(self, category): """ Returns all modules in a given category, for instance "serializer", or "cli". Cobbler internal use only. """ return module_loader.get_modules_in_category(category)
# ==========================================================================
[docs] def authenticate(self, user, password): """ (Remote) access control. Cobbler internal use only. """ rc = self.authn.authenticate(self, user, password) self.log("authenticate", [user, rc]) return rc
[docs] def authorize(self, user, resource, arg1=None, arg2=None): """ (Remote) access control. Cobbler internal use only. """ rc = self.authz.authorize(self, user, resource, arg1, arg2) self.log("authorize", [user, resource, arg1, arg2, rc], debug=True) return rc
# ==========================================================================
[docs] def build_iso(self, iso=None, profiles=None, systems=None, buildisodir=None, distro=None, standalone=None, airgapped=None, source=None, exclude_dns=None, mkisofs_opts=None, logger=None): builder = buildiso.BuildIso(self._collection_mgr, logger=logger) builder.run( iso=iso, profiles=profiles, systems=systems, buildisodir=buildisodir, distro=distro, standalone=standalone, airgapped=airgapped, source=source, exclude_dns=exclude_dns, mkisofs_opts=mkisofs_opts )
# ========================================================================== # ==========================================================================
[docs] def replicate(self, cobbler_master=None, port="80", distro_patterns="", profile_patterns="", system_patterns="", repo_patterns="", image_patterns="", mgmtclass_patterns=None, package_patterns=None, file_patterns=None, prune=False, omit_data=False, sync_all=False, use_ssl=False, logger=None): """ Pull down data/configs from a remote cobbler server that is a master to this server. """ replicator = replicate.Replicate(self._collection_mgr, logger=logger) return replicator.run( cobbler_master=cobbler_master, port=port, distro_patterns=distro_patterns, profile_patterns=profile_patterns, system_patterns=system_patterns, repo_patterns=repo_patterns, image_patterns=image_patterns, mgmtclass_patterns=mgmtclass_patterns, package_patterns=package_patterns, file_patterns=file_patterns, prune=prune, omit_data=omit_data, sync_all=sync_all, use_ssl=use_ssl )
# ==========================================================================
[docs] def report(self, report_what=None, report_name=None, report_type=None, report_fields=None, report_noheaders=None): """ Report functionality for cobbler """ reporter = report.Report(self._collection_mgr) return reporter.run(report_what=report_what, report_name=report_name, report_type=report_type, report_fields=report_fields, report_noheaders=report_noheaders)
# ==========================================================================
[docs] def power_system(self, system, power_operation, user=None, password=None, logger=None): """ Power on / power off / get power status /reboot a system. @param str system Cobbler system @param str power_operation power operation. Valid values: on, off, reboot, status @param str token Cobbler authentication token @param str user power management user @param str password power management password @param Logger logger logger @return bool if operation was successful """ if power_operation == "on": self.power_mgr.power_on(system, user=user, password=password, logger=logger) elif power_operation == "off": self.power_mgr.power_off(system, user=user, password=password, logger=logger) elif power_operation == "status": return self.power_mgr.get_power_status(system, user=user, password=password, logger=logger) elif power_operation == "reboot": self.power_mgr.reboot(system, user=user, password=password, logger=logger) else: utils.die(self.logger, "invalid power operation '%s', expected on/off/status/reboot" % power_operation) return None
# ==========================================================================
[docs] def clear_logs(self, system, logger=None): """ Clears console and anamon logs for system """ log.LogTool(self._collection_mgr, system, self, logger=logger).clear()