def _sync_airgapped_repos(self, airgapped: bool, repo_names_to_copy: dict): """ Syncs all repositories locally available into the image if the is supposed to be airgapped. :param airgapped: If false this method is doing nothing. :param repo_names_to_copy: The names of the repositories which should be included. :raises RuntimeError: In case the rsync of the repository was not successful. """ if airgapped: # copy any repos found in profiles or systems to the iso build repodir = os.path.abspath( os.path.join(self.isolinuxdir, "..", "repo_mirror")) if not os.path.exists(repodir): os.makedirs(repodir) for repo_name in repo_names_to_copy: self.logger.info(" - copying repo '%s' for airgapped ISO", repo_name) rsync_successful = utils.rsync_files( repo_names_to_copy[repo_name], os.path.join(repodir, repo_name), "--exclude=TRANS.TBL --exclude=cache/ --no-g", quiet=True, ) if not rsync_successful: raise RuntimeError('rsync of repo "%s" failed' % repo_name)
def test_rsync_files(): # Arrange # TODO: Generate test env with data to check testsrc = "" testdst = "" testargs = "" # Act result = utils.rsync_files(testsrc, testdst, testargs) # Assert assert result # TODO: Check if the files were copied correctly. assert False
def generate_standalone_iso(self, imagesdir, isolinuxdir, distname, filesource, airgapped: bool, profiles): """ Create bootable CD image to be used for handsoff CD installtions :param imagesdir: Unused Parameter. :param isolinuxdir: The parent directory where the file isolinux.cfg is located at. :param distname: The name of the Cobbler distribution. :param filesource: Not clear what this exactly does :param airgapped: Whether the repositories have to be locally available or the internet is reachable. :param profiles: The list of profiles to include. """ # Get the distro object for the requested distro and then get all of its descendants (profiles/sub-profiles/ # systems) with sort=True for profile/system heirarchy to allow menu indenting distro = self.api.find_distro(distname) if distro is None: utils.die("distro %s was not found, aborting" % distname) descendants = distro.get_descendants(sort=True) profiles = utils.input_string_or_list(profiles) if filesource is None: # Try to determine the source from the distro kernel path self.logger.debug("trying to locate source for distro") found_source = False (source_head, source_tail) = os.path.split(distro.kernel) while source_tail != '': if source_head == os.path.join(self.api.settings().webdir, "distro_mirror"): filesource = os.path.join(source_head, source_tail) found_source = True self.logger.debug("found source in %s" % filesource) break (source_head, source_tail) = os.path.split(source_head) # Can't find the source, raise an error if not found_source: utils.die("Error, no installation source found. When building a standalone ISO, you must specify a " "--source if the distro install tree is not hosted locally") self.logger.info("copying kernels and initrds for standalone distro") self.copy_boot_files(distro, isolinuxdir, None) self.logger.info("generating an isolinux.cfg") isolinuxcfg = os.path.join(isolinuxdir, "isolinux.cfg") cfg = open(isolinuxcfg, "w+") cfg.write(self.iso_template) if airgapped: repo_names_to_copy = {} for descendant in descendants: # if a list of profiles was given, skip any others and their systems if profiles and ((descendant.COLLECTION_TYPE == 'profile' and descendant.name not in profiles) or (descendant.COLLECTION_TYPE == 'system' and descendant.profile not in profiles)): continue menu_indent = 0 if descendant.COLLECTION_TYPE == 'system': menu_indent = 4 data = utils.blender(self.api, False, descendant) # SUSE is not using 'text'. Instead 'textmode' is used as kernel option. if distro is not None: utils.kopts_overwrite(data['kernel_options'], self.settings.server, distro.breed) cfg.write("\n") cfg.write("LABEL %s\n" % descendant.name) if menu_indent: cfg.write(" MENU INDENT %d\n" % menu_indent) cfg.write(" MENU LABEL %s\n" % descendant.name) cfg.write(" kernel %s\n" % os.path.basename(distro.kernel)) append_line = " append initrd=%s" % os.path.basename(distro.initrd) if distro.breed == "redhat": append_line += " inst.ks=cdrom:/isolinux/%s.cfg" % descendant.name if distro.breed == "suse": append_line += " autoyast=file:///isolinux/%s.cfg install=cdrom:///" % descendant.name if "install" in data["kernel_options"]: del data["kernel_options"]["install"] if distro.breed in ["ubuntu", "debian"]: append_line += " auto-install/enable=true preseed/file=/cdrom/isolinux/%s.cfg" % descendant.name # add remaining kernel_options to append_line append_line += self.add_remaining_kopts(data["kernel_options"]) cfg.write(append_line) if descendant.COLLECTION_TYPE == 'profile': autoinstall_data = self.api.autoinstallgen.generate_autoinstall_for_profile(descendant.name) elif descendant.COLLECTION_TYPE == 'system': autoinstall_data = self.api.autoinstallgen.generate_autoinstall_for_system(descendant.name) if distro.breed == "redhat": cdregex = re.compile(r"^\s*url .*\n", re.IGNORECASE | re.MULTILINE) autoinstall_data = cdregex.sub("cdrom\n", autoinstall_data, count=1) if airgapped: descendant_repos = data['repos'] for repo_name in descendant_repos: repo_obj = self.api.find_repo(repo_name) error_fmt = (descendant.COLLECTION_TYPE + " " + descendant.name + " refers to repo " + repo_name + ", which %%s; cannot build airgapped ISO") if repo_obj is None: utils.die(error_fmt % "does not exist") if not repo_obj.mirror_locally: utils.die(error_fmt % "is not configured for local mirroring") # FIXME: don't hardcode mirrordir = os.path.join(self.settings.webdir, "repo_mirror", repo_obj.name) if not os.path.exists(mirrordir): utils.die(error_fmt % "has a missing local mirror directory") repo_names_to_copy[repo_obj.name] = mirrordir # update the baseurl in autoinstall_data to use the cdrom copy of this repo reporegex = re.compile(r"^(\s*repo --name=" + repo_obj.name + " --baseurl=).*", re.MULTILINE) autoinstall_data = reporegex.sub(r"\1" + "file:///mnt/source/repo_mirror/" + repo_obj.name, autoinstall_data) # rewrite any split-tree repos, such as in redhat, to use cdrom srcreporegex = re.compile(r"^(\s*repo --name=\S+ --baseurl=).*/cobbler/distro_mirror/" + distro.name + r"/?(.*)", re.MULTILINE) autoinstall_data = srcreporegex.sub(r"\1" + "file:///mnt/source" + r"\2", autoinstall_data) autoinstall_name = os.path.join(isolinuxdir, "%s.cfg" % descendant.name) with open(autoinstall_name, "w+") as autoinstall_file: autoinstall_file.write(autoinstall_data) self.logger.info("done writing config") cfg.write("\n") cfg.write("MENU END\n") cfg.close() if airgapped: # copy any repos found in profiles or systems to the iso build repodir = os.path.abspath(os.path.join(isolinuxdir, "..", "repo_mirror")) if not os.path.exists(repodir): os.makedirs(repodir) for repo_name in repo_names_to_copy: src = repo_names_to_copy[repo_name] dst = os.path.join(repodir, repo_name) self.logger.info(" - copying repo '" + repo_name + "' for airgapped ISO") ok = utils.rsync_files(src, dst, "--exclude=TRANS.TBL --exclude=cache/ --no-g", quiet=True) if not ok: utils.die("rsync of repo '" + repo_name + "' failed") # copy distro files last, since they take the most time cmd = "rsync -rlptgu --exclude=boot.cat --exclude=TRANS.TBL --exclude=isolinux/ %s/ %s/../"\ % (filesource, isolinuxdir) self.logger.info("- copying distro %s files (%s)" % (distname, cmd)) rc = utils.subprocess_call(cmd, shell=True) if rc: utils.die("rsync of distro files failed")