diff --git a/cobbler/action_import.py b/cobbler/action_import.py index babdafd..b0be882 100644 --- a/cobbler/action_import.py +++ b/cobbler/action_import.py @@ -37,6 +37,7 @@ WGET_CMD = "wget --mirror --no-parent --no-host-directories --directory-prefix % RSYNC_CMD = "rsync -a %s '%s' %s/ks_mirror/%s --exclude-from=/etc/cobbler/rsync.exclude --progress" TRY_LIST = [ + "pool", "Fedora", "Packages", "RedHat", "Client", "Server", "Centos", "CentOS", "Fedora/RPMS", "RedHat/RPMS", "Client/RPMS", "Server/RPMS", "Centos/RPMS", "CentOS/RPMS", "RPMS" @@ -44,7 +45,10 @@ TRY_LIST = [ class Importer: - def __init__(self,api,config,mirror,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None): + validarchs = [ "x86", "ia64", "x86_64", "s390x" ] + archmaps = { "i386" : "x86" , "amd64" : "x86_64" , "386" : "" , "amd" : "" } + + def __init__(self,api,config,mirror,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None,breed=None): """ Performs an import of a install tree (or trees) from the given mirror address. The prefix of the distro is to be specified @@ -68,6 +72,7 @@ class Importer: self.kickstart_file = kickstart_file self.rsync_flags = rsync_flags self.arch = arch + self.breed = breed # ---------------------------------------------------------------------- @@ -78,11 +83,8 @@ class Importer: raise CX(_("import failed. no --name specified")) if self.arch is not None: self.arch = self.arch.lower() - if self.arch not in [ "i386", "x86", "ia64", "x86_64", "s390x" ]: - raise CX(_("arch must be x86, x86_64, s390x, or ia64")) - if self.arch == "x86": - # be consistent - self.arch = "i386" + if self.arch not in self.validarchs: + raise CX(_("arch must be one of %s")) % ", ".join(validarchs) mpath = os.path.join(self.settings.webdir, "ks_mirror", self.mirror_name) @@ -92,16 +94,11 @@ class Importer: if self.arch: # append the arch path to the name if the arch is not already # found in the name. - found = False - for x in [ "ia64", "i386", "x86_64", "x86", "s390x" ]: + for x in self.validarchs: if self.mirror_name.lower().find(x) != -1: - found = True break - if not found: + else: self.mirror_name = self.mirror_name + "-" + self.arch - - if self.mirror_name is None: - raise CX(_("import failed. no --name specified")) # make the output path and mirror content but only if not specifying that a network # accessible support location already exists @@ -139,22 +136,22 @@ class Importer: if not self.network_root.endswith("/"): self.network_root = self.network_root + "/" self.path = self.mirror - found_root = False valid_roots = [ "nfs://", "ftp://", "http://" ] for valid_root in valid_roots: if self.network_root.startswith(valid_root): - found_root = True + break + else: + raise CX(_("Network root given to --available-as must be %s")) % ", ".join(valid_roots) if self.network_root.startswith("nfs://"): try: (a,b,rest) = self.network_root.split(":",3) except: raise CX(_("Network root given to --available-as is missing a colon, please see the manpage example.")) - if not found_root: - raise CX(_("Network root given to --available-as must be nfs://, ftp://, or http://")) self.processed_repos = {} print _("---------------- (adding distros)") + print "to %s" % self.path os.path.walk(self.path, self.distro_adder, {}) if self.network_root is None: @@ -205,7 +202,8 @@ class Importer: if (self.kickstart_file == None): kdir = os.path.dirname(distro.kernel) - base_dir = "/".join(kdir.split("/")[0:-2]) + # FIXME : Some special handling for network_root might be required as in get_proposed_name, + base_dir = "/".join(kdir.split("/")[:6]) for try_entry in TRY_LIST: try_dir = os.path.join(base_dir, try_entry) @@ -220,6 +218,18 @@ class Importer: (flavor, major, minor) = results # print _("- finding default kickstart template for %(flavor)s %(major)s") % { "flavor" : flavor, "major" : major } kickstart = self.set_variance(profile, flavor, major, minor, distro) + if not rpms: + # search for base-files or base-installer ? + rpms = glob.glob(os.path.join(try_dir, "main/b/base-files" , "base-files_*")) + for rpm in rpms: + results = self.scan_deb_filename(rpm) + if results is None: + continue + (flavor, major, minor) = results + if self.breed and self.breed != flavor: + raise CX(_("Error: given breed does not match imported tree")) + # print _("- finding default kickstart template for %(flavor)s %(major)s") % { "flavor" : flavor, "major" : major } + kickstart = self.set_variance(profile, flavor, major, minor, distro) else: print _("- using kickstart file %s") % self.kickstart_file profile.set_kickstart(self.kickstart_file) @@ -329,6 +339,14 @@ class Importer: if major >= 5: return profile.set_kickstart("/etc/cobbler/sample.ks") + if flavor == "debian": + + distro.set_breed("debian") + dist_names = { '4.0' : "Etch" , '5.0' : "Lenny" } + dist_vers = "%s.%s" % ( major , minor ) + distro.set_os_version("debian%s" % dist_names[dist_vers]) + return profile.set_kickstart("/etc/cobbler/sample.seed") + print _("- using default kickstart file choice") return profile.set_kickstart("/etc/cobbler/legacy.ks") @@ -378,6 +396,27 @@ class Importer: minor = float(accum[1]) return (flavor, major, minor) + def scan_deb_filename(self, deb): + """ + Determine what the distro is based on the base-files dpkg filename. + """ + + deb = os.path.basename(deb) + + # get all the tokens and try to guess a version + accum = [] + tokens = deb.split("_") + tokens2 = tokens[1].split(".") + for t2 in tokens2: + try: + val = int(t2) + accum.append(val) + except: + pass + accum.append(0) + + return ("debian", accum[0], accum[1]) + # ---------------------------------------------------------------------- def distro_adder(self,foo,dirname,fnames): @@ -389,6 +428,8 @@ class Importer: fullname = os.path.join(dirname,x) if os.path.islink(fullname) and os.path.isdir(fullname): + if os.path.realpath(fullname) == os.path.realpath(dirname): + continue print "- following symlink: %s" % fullname os.path.walk(fullname, self.distro_adder, {}) @@ -398,8 +439,10 @@ class Importer: kernel = os.path.join(dirname,x) if initrd is not None and kernel is not None and dirname.find("isolinux") == -1: self.add_entry(dirname,kernel,initrd) path_parts = kernel.split("/")[:-2] comps_path = "/".join(path_parts) + initrd = None + kernel = None @@ -411,7 +454,8 @@ class Importer: print _("- traversing distro %s") % distro.name if distro.kernel.find("ks_mirror") != -1: basepath = os.path.dirname(distro.kernel) - top = "/".join(basepath.split("/")[0:-2]) # up one level + # FIXME : Some special handling for network_root might be required as in get_proposed_name, + top = "/".join(basepath.split("/")[:6]) print _("- descent into %s") % top os.path.walk(top, self.repo_scanner, distro) else: @@ -568,9 +612,6 @@ class Importer: def get_proposed_name(self,dirname,pxe_arch): archname = pxe_arch - if archname == "x86": - # be consistent - archname = "i386" # FIXME: this is new, needs testing ... if self.network_root is not None: name = "-".join(self.path_tail(self.path,dirname).split("/")) @@ -587,16 +628,11 @@ class Importer: name = name.replace("ks_mirror-","") name = name.replace("-pxeboot","") name = name.replace("--","-") - name = name.replace("-i386","") - name = name.replace("_i386","") - name = name.replace("-x86_64","") - name = name.replace("_x86_64","") - name = name.replace("-ia64","") - name = name.replace("_ia64","") - name = name.replace("-x86","") - name = name.replace("_x86","") - name = name.replace("-s390x","") - name = name.replace("_s390x","") + for separator in [ '-' , '_' , '.' ] : + for arch in self.validarchs: + name = name.replace("%s%s" % ( separator , arch ),"") + for arch in self.archmaps.keys(): + name = name.replace("%s%s" % ( separator , arch ),"") # ensure arch is on the end, regardless of path used. name = name + "-" + archname @@ -608,53 +644,39 @@ class Importer: """ # don't care about certain directories - match = False for x in TRY_LIST: if dirname.find(x) != -1: - match = True - continue - if not match: + break + else: return # try to find a kernel header RPM and then look at it's arch. for x in fnames: - if not x.endswith("rpm"): + if not x.endswith("rpm") and not x.endswith("deb"): continue if x.find("kernel-header") != -1: print _("- kernel header found: %s") % x - if x.find("i386") != -1: - foo["result"] = "i386" - return - elif x.find("x86_64") != -1: - foo["result"] = "x86_64" - return - elif x.find("ia64") != -1: - foo["result"] = "ia64" - return - elif x.find("s390") != -1: - foo["result"] = "s390x" - return + for arch in self.validarchs: + if x.find(arch) != -1: + foo.append( arch ) + for arch in self.archmaps.keys(): + if x.find(arch) != -1 and self.archmaps[arch]: + foo.append( self.archmaps[arch] ) # This extra code block is a temporary fix for rhel4.x 64bit [x86_64] # distro ARCH identification-- L.M. # NOTE: eventually refactor to merge in with the above block for x in fnames: - if not x.endswith("rpm"): + if not x.endswith("rpm") and not x.endswith("deb"): continue if x.find("kernel-largesmp") != -1: - print _("- kernel header found: %s") % x - if x.find("i386") != -1: - foo["result"] = "i386" - return - elif x.find("x86_64") != -1: - foo["result"] = "x86_64" - return - elif x.find("ia64") != -1: - foo["result"] = "ia64" - return - elif x.find("s390") != -1: - foo["result"] = "s390x" - return + print _("- kernel header found II: %s") % x + for arch in self.validarchs: + if x.find(arch) != -1: + foo.append( arch ) + for arch in self.archmaps.keys() and self.archmaps[arch]: + if x.find(arch) != -1: + foo.append( self.archmaps[arch] ) def learn_arch_from_tree(self,dirname): """ @@ -663,21 +685,22 @@ class Importer: figure out the arch name. This is important for producing predictable distro names (and profile names) from differing import sources """ - dirname2 = "/".join(dirname.split("/")[:-2]) # up two from images, then down as many as needed + # FIXME : Some special handling for network_root might be required as in get_proposed_name, + dirname2 = "/".join(dirname.split("/")[:6]) print _("- scanning %s for architecture info") % dirname2 - result = { "result" : "i386" } # default, but possibly not correct ... + result = [] os.path.walk(dirname2, self.arch_walker, result) - return result["result"] + if len(result) > 1 : + raise CX(_("Importing CD/DVD with multiple architectures is not supported")) + return result[0] def get_pxe_arch(self,dirname): t = dirname.lower() - if t.find("x86_64") != -1: - return "x86_64" - if t.find("ia64") != -1: - return "ia64" - if t.find("i386") != -1 or t.find("386") != -1 or t.find("x86") != -1: - return "i386" - if t.find("s390") != -1: - return "s390x" + for arch in self.validarchs: + if t.find(arch) != -1: + return arch + for arch in self.archmaps.keys(): + if t.find(arch) != -1 and self.archmaps[arch]: + return self.archmaps[arch] return self.learn_arch_from_tree(dirname) diff --git a/cobbler/api.py b/cobbler/api.py index 3defb05..6e80185 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -410,7 +410,7 @@ class BootAPI: statusifier = action_status.BootStatusReport(self._config,mode) return statusifier.run() - def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None): + def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None,breed=None): """ Automatically import a directory tree full of distribution files. mirror_url can be a string that represents a path, a user@host @@ -420,7 +420,7 @@ class BootAPI: """ self.log("import_tree",[mirror_url, mirror_name, network_root, kickstart_file, rsync_flags]) importer = action_import.Importer( - self, self._config, mirror_url, mirror_name, network_root, kickstart_file, rsync_flags, arch + self, self._config, mirror_url, mirror_name, network_root, kickstart_file, rsync_flags, arch, breed ) return importer.run() diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py index f92094a..fdc8d69 100644 --- a/cobbler/modules/cli_misc.py +++ b/cobbler/modules/cli_misc.py @@ -74,6 +74,7 @@ class ImportFunction(commands.CobblerFunction): def add_options(self, p, args): p.add_option("--arch", dest="arch", help="explicitly specify the architecture being imported (RECOMENDED)") + p.add_option("--breed", dest="breed", help="explicitly specify the breed being imported (RECOMENDED)") p.add_option("--path", dest="mirror", help="local path or rsync location (REQUIRED)") p.add_option("--mirror", dest="mirror_alt", help="alias for --path") p.add_option("--name", dest="name", help="name, ex 'RHEL-5', (REQUIRED)") @@ -94,7 +95,8 @@ class ImportFunction(commands.CobblerFunction): network_root=self.options.available_as, kickstart_file=self.options.kickstart_file, rsync_flags=self.options.rsync_flags, - arch=self.options.arch + arch=self.options.arch, + breed=self.options.breed )