Example #1
0
    def __setattr__(self, name, value):
        if name in DEFAULTS:
            try:
                if DEFAULTS[name][1] == "str":
                    value = str(value)
                elif DEFAULTS[name][1] == "int":
                    value = int(value)
                elif DEFAULTS[name][1] == "bool":
                    if utils.input_boolean(value):
                        value = 1
                    else:
                        value = 0
                elif DEFAULTS[name][1] == "float":
                    value = float(value)
                elif DEFAULTS[name][1] == "list":
                    value = utils.input_string_or_list(value)
                elif DEFAULTS[name][1] == "dict":
                    value = utils.input_string_or_dict(value)[1]
            except:
                raise AttributeError

            self.__dict__[name] = value
            if not utils.update_settings_file(self.to_dict()):
                raise AttributeError

            return 0
        else:
            raise AttributeError
Example #2
0
    def __setattr__(self, name, value):
        if name in DEFAULTS:
            try:
                if DEFAULTS[name][1] == "str":
                    value = str(value)
                elif DEFAULTS[name][1] == "int":
                    value = int(value)
                elif DEFAULTS[name][1] == "bool":
                    if utils.input_boolean(value):
                        value = 1
                    else:
                        value = 0
                elif DEFAULTS[name][1] == "float":
                    value = float(value)
                elif DEFAULTS[name][1] == "list":
                    value = utils.input_string_or_list(value)
                elif DEFAULTS[name][1] == "dict":
                    value = utils.input_string_or_dict(value)[1]
            except:
                raise AttributeError

            self.__dict__[name] = value
            if not utils.update_settings_file(self.to_dict()):
                raise AttributeError

            return 0
        else:
            raise AttributeError
Example #3
0
 def __getattr__(self, name):
     try:
         if name == "kernel_options":
             # backwards compatibility -- convert possible string value to dict
             (success, result) = utils.input_string_or_dict(self.__dict__[name], allow_multiples=False)
             self.__dict__[name] = result
             return result
         return self.__dict__[name]
     except:
         if name in DEFAULTS:
             lookup = DEFAULTS[name][0]
             self.__dict__[name] = lookup
             return lookup
         else:
             raise AttributeError
Example #4
0
 def __getattr__(self, name):
     try:
         if name == "kernel_options":
             # backwards compatibility -- convert possible string value to dict
             (success, result) = utils.input_string_or_dict(self.__dict__[name], allow_multiples=False)
             self.__dict__[name] = result
             return result
         return self.__dict__[name]
     except:
         if name in DEFAULTS:
             lookup = DEFAULTS[name][0]
             self.__dict__[name] = lookup
             return lookup
         else:
             raise AttributeError
Example #5
0
    def write_templates(self, obj, write_file=False, path=None):
        """
        A semi-generic function that will take an object
        with a template_files dict {source:destiation}, and
        generate a rendered file.  The write_file option
        allows for generating of the rendered output without
        actually creating any files.

        The return value is a dict of the destination file
        names (after variable substitution is done) and the
        data in the file.
        """
        self.logger.info("Writing template files for %s" % obj.name)

        results = {}

        try:
            templates = obj.template_files
        except:
            return results

        blended = utils.blender(self.api, False, obj)

        if obj.COLLECTION_TYPE == "distro":
            if re.search("esxi[56]", obj.os_version) is not None:
                realbootcfg = open(os.path.join(os.path.dirname(obj.kernel), 'boot.cfg')).read()
                bootmodules = re.findall(r'modules=(.*)', realbootcfg)
                for modules in bootmodules:
                    blended['esx_modules'] = modules.replace('/', '')

        ksmeta = blended.get("ks_meta", {})
        try:
            del blended["ks_meta"]
        except:
            pass
        blended.update(ksmeta)          # make available at top level

        templates = blended.get("template_files", {})
        try:
            del blended["template_files"]
        except:
            pass
        blended.update(templates)       # make available at top level

        (success, templates) = utils.input_string_or_dict(templates)

        if not success:
            return results

        # FIXME: img_path and local_img_path should probably be moved
        #        up into the blender function to ensure they're consistently
        #        available to templates across the board
        if blended["distro_name"]:
            blended['img_path'] = os.path.join("/images", blended["distro_name"])
            blended['local_img_path'] = os.path.join(utils.tftpboot_location(), "images", blended["distro_name"])

        for template in templates.keys():
            dest = templates[template]
            if dest is None:
                continue

            # Run the source and destination files through
            # templar first to allow for variables in the path
            template = self.templar.render(template, blended, None).strip()
            dest = os.path.normpath(self.templar.render(dest, blended, None).strip())
            # Get the path for the destination output
            dest_dir = os.path.normpath(os.path.dirname(dest))

            # If we're looking for a single template, skip if this ones
            # destination is not it.
            if path is not None and path != dest:
                continue

            # If we are writing output to a file, we allow files tobe
            # written into the tftpboot directory, otherwise force all
            # templated configs into the rendered directory to ensure that
            # a user granted cobbler privileges via sudo can't overwrite
            # arbitrary system files (This also makes cleanup easier).
            if os.path.isabs(dest_dir) and write_file:
                if dest_dir.find(utils.tftpboot_location()) != 0:
                    raise CX(" warning: template destination (%s) is outside %s, skipping." % (dest_dir, utils.tftpboot_location()))
                    continue
            elif write_file:
                dest_dir = os.path.join(self.settings.webdir, "rendered", dest_dir)
                dest = os.path.join(dest_dir, os.path.basename(dest))
                if not os.path.exists(dest_dir):
                    utils.mkdir(dest_dir)

            # Check for problems
            if not os.path.exists(template):
                raise CX("template source %s does not exist" % template)
                continue
            elif write_file and not os.path.isdir(dest_dir):
                raise CX("template destination (%s) is invalid" % dest_dir)
                continue
            elif write_file and os.path.exists(dest):
                raise CX("template destination (%s) already exists" % dest)
                continue
            elif write_file and os.path.isdir(dest):
                raise CX("template destination (%s) is a directory" % dest)
                continue
            elif template == "" or dest == "":
                raise CX("either the template source or destination was blank (unknown variable used?)" % dest)
                continue

            template_fh = open(template)
            template_data = template_fh.read()
            template_fh.close()

            buffer = self.templar.render(template_data, blended, None)
            results[dest] = buffer

            if write_file:
                self.logger.info("generating: %s" % dest)
                fd = open(dest, "w")
                fd.write(buffer)
                fd.close()

        return results
Example #6
0
    def write_pxe_file(self, filename, system, profile, distro, arch,
                       image=None, include_header=True, metadata=None, format="pxe"):
        """
        Write a configuration file for the boot loader(s).
        More system-specific configuration may come in later, if so
        that would appear inside the system object in api.py

        Can be used for different formats, "pxe" (default) and "grub".
        """
        if arch is None:
            raise "missing arch"

        if image and not os.path.exists(image.file):
            return None     # nfs:// URLs or something, can't use for TFTP

        if metadata is None:
            metadata = {}

        (rval, settings) = utils.input_string_or_dict(self.settings.to_dict())
        if rval:
            for key in settings.keys():
                metadata[key] = settings[key]
        # ---
        # just some random variables
        template = None
        buffer = ""

        # ---
        kickstart_path = None
        kernel_path = None
        initrd_path = None
        img_path = None

        if image is None:
            # not image based, it's something normalish

            img_path = os.path.join("/images", distro.name)

            if 'nexenta' == distro.breed:
                kernel_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'kernel', 'amd64', os.path.basename(distro.kernel))
                initrd_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'amd64', os.path.basename(distro.initrd))
            else:
                kernel_path = os.path.join("/images", distro.name, os.path.basename(distro.kernel))
                initrd_path = os.path.join("/images", distro.name, os.path.basename(distro.initrd))

            # Find the kickstart if we inherit from another profile
            if system:
                blended = utils.blender(self.api, True, system)
            else:
                blended = utils.blender(self.api, True, profile)
            kickstart_path = blended.get("kickstart", "")

            # update metadata with all known information
            # this allows for more powerful templating
            metadata.update(blended)

        else:
            # this is an image we are making available, not kernel+initrd
            if image.image_type == "direct":
                kernel_path = os.path.join("/images2", image.name)
            elif image.image_type == "memdisk":
                kernel_path = "/memdisk"
                initrd_path = os.path.join("/images2", image.name)
            else:
                # CD-ROM ISO or virt-clone image? We can't PXE boot it.
                kernel_path = None
                initrd_path = None

        if img_path is not None and "img_path" not in metadata:
            metadata["img_path"] = img_path
        if kernel_path is not None and "kernel_path" not in metadata:
            metadata["kernel_path"] = kernel_path
        if initrd_path is not None and "initrd_path" not in metadata:
            metadata["initrd_path"] = initrd_path

        # ---
        # choose a template
        if system:
            if format == "grub":
                if system.netboot_enabled:
                    template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubsystem.template")
                else:
                    local = os.path.join(self.settings.boot_loader_conf_template_dir, "grublocal.template")
                    if os.path.exists(local):
                        template = local
            else:   # pxe
                if system.netboot_enabled:
                    template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem.template")

                    if arch.startswith("ppc"):
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_ppc.template")
                    elif arch.startswith("arm"):
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_arm.template")
                    elif distro and distro.os_version.startswith("esxi"):
                        # ESXi uses a very different pxe method, using more files than
                        # a standard kickstart and different options - so giving it a dedicated
                        # PXE template makes more sense than shoe-horning it into the existing
                        # templates
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_esxi.template")
                else:
                    # local booting on ppc requires removing the system-specific dhcpd.conf filename
                    if arch is not None and arch.startswith("ppc"):
                        # Disable yaboot network booting for all interfaces on the system
                        for (name, interface) in system.interfaces.iteritems():

                            filename = "%s" % utils.get_config_filename(system, interface=name).lower()

                            # Remove symlink to the yaboot binary
                            f3 = os.path.join(self.bootloc, "ppc", filename)
                            if os.path.lexists(f3):
                                utils.rmfile(f3)

                            # Remove the interface-specific config file
                            f3 = os.path.join(self.bootloc, "etc", filename)
                            if os.path.lexists(f3):
                                utils.rmfile(f3)

                        # Yaboot/OF doesn't support booting locally once you've
                        # booted off the network, so nothing left to do
                        return None
                    else:
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxelocal.template")
        else:
            # not a system record, so this is a profile record or an image
            if arch.startswith("arm"):
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_arm.template")
            elif format == "grub":
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubprofile.template")
            elif distro and distro.os_version.startswith("esxi"):
                # ESXi uses a very different pxe method, see comment above in the system section
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_esxi.template")
            elif 'nexenta' == format:
                template = os.path.join(self.settings.boot_loader_conf_template_dir, 'nexenta_profile.template')
            else:
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile.template")


        if kernel_path is not None:
            metadata["kernel_path"] = kernel_path
        if initrd_path is not None:
            metadata["initrd_path"] = initrd_path

        # generate the kernel options and append line:
        kernel_options = self.build_kernel_options(system, profile, distro,
                                                   image, arch, kickstart_path)
        metadata["kernel_options"] = kernel_options

        if distro and distro.os_version.startswith("esxi") and filename is not None:
            append_line = "BOOTIF=%s" % (os.path.basename(filename))
        elif "initrd_path" in metadata and (not arch or arch not in ["ppc", "ppc64", "arm"]):
            append_line = "append initrd=%s" % (metadata["initrd_path"])
        else:
            append_line = "append "
        append_line = "%s%s" % (append_line, kernel_options)
        if arch.startswith("ppc"):
            # remove the prefix "append"
            # TODO: this looks like it's removing more than append, really
            # not sure what's up here...
            append_line = append_line[7:]
        if distro and distro.os_version.startswith("xenserver620"):
            append_line = "%s" % (kernel_options)
        metadata["append_line"] = append_line

        # store variables for templating
        metadata["menu_label"] = ""
        if profile:
            if arch not in ["ppc", "ppc64"]:
                metadata["menu_label"] = "MENU LABEL %s" % profile.name
                metadata["profile_name"] = profile.name
        elif image:
            metadata["menu_label"] = "MENU LABEL %s" % image.name
            metadata["profile_name"] = image.name

        if system:
            metadata["system_name"] = system.name


        # get the template
        if kernel_path is not None:
            template_fh = open(template)
            template_data = template_fh.read()
            template_fh.close()
        else:
            # this is something we can't PXE boot
            template_data = "\n"

        # save file and/or return results, depending on how called.
        buffer = self.templar.render(template_data, metadata, None)
        if filename is not None:
            self.logger.info("generating: %s" % filename)
            fd = open(filename, "w")
            fd.write(buffer)
            fd.close()
        return buffer
Example #7
0
    def write_templates(self, obj, write_file=False, path=None):
        """
        A semi-generic function that will take an object
        with a template_files dict {source:destiation}, and
        generate a rendered file.  The write_file option
        allows for generating of the rendered output without
        actually creating any files.

        The return value is a dict of the destination file
        names (after variable substitution is done) and the
        data in the file.
        """
        self.logger.info("Writing template files for %s" % obj.name)

        results = {}

        try:
            templates = obj.template_files
        except:
            return results

        blended = utils.blender(self.api, False, obj)

        if obj.COLLECTION_TYPE == "distro":
            if re.search("esxi[56]", obj.os_version) is not None:
                realbootcfg = open(os.path.join(os.path.dirname(obj.kernel), 'boot.cfg')).read()
                bootmodules = re.findall(r'modules=(.*)', realbootcfg)
                for modules in bootmodules:
                    blended['esx_modules'] = modules.replace('/', '')

        ksmeta = blended.get("ks_meta", {})
        try:
            del blended["ks_meta"]
        except:
            pass
        blended.update(ksmeta)          # make available at top level

        templates = blended.get("template_files", {})
        try:
            del blended["template_files"]
        except:
            pass
        blended.update(templates)       # make available at top level

        (success, templates) = utils.input_string_or_dict(templates)

        if not success:
            return results

        # FIXME: img_path and local_img_path should probably be moved
        #        up into the blender function to ensure they're consistently
        #        available to templates across the board
        if blended["distro_name"]:
            blended['img_path'] = os.path.join("/images", blended["distro_name"])
            blended['local_img_path'] = os.path.join(utils.tftpboot_location(), "images", blended["distro_name"])

        for template in templates.keys():
            dest = templates[template]
            if dest is None:
                continue

            # Run the source and destination files through
            # templar first to allow for variables in the path
            template = self.templar.render(template, blended, None).strip()
            dest = os.path.normpath(self.templar.render(dest, blended, None).strip())
            # Get the path for the destination output
            dest_dir = os.path.normpath(os.path.dirname(dest))

            # If we're looking for a single template, skip if this ones
            # destination is not it.
            if path is not None and path != dest:
                continue

            # If we are writing output to a file, we allow files tobe
            # written into the tftpboot directory, otherwise force all
            # templated configs into the rendered directory to ensure that
            # a user granted cobbler privileges via sudo can't overwrite
            # arbitrary system files (This also makes cleanup easier).
            if os.path.isabs(dest_dir) and write_file:
                if dest_dir.find(utils.tftpboot_location()) != 0:
                    raise CX(" warning: template destination (%s) is outside %s, skipping." % (dest_dir, utils.tftpboot_location()))
                    continue
            elif write_file:
                dest_dir = os.path.join(self.settings.webdir, "rendered", dest_dir)
                dest = os.path.join(dest_dir, os.path.basename(dest))
                if not os.path.exists(dest_dir):
                    utils.mkdir(dest_dir)

            # Check for problems
            if not os.path.exists(template):
                raise CX("template source %s does not exist" % template)
                continue
            elif write_file and not os.path.isdir(dest_dir):
                raise CX("template destination (%s) is invalid" % dest_dir)
                continue
            elif write_file and os.path.exists(dest):
                raise CX("template destination (%s) already exists" % dest)
                continue
            elif write_file and os.path.isdir(dest):
                raise CX("template destination (%s) is a directory" % dest)
                continue
            elif template == "" or dest == "":
                raise CX("either the template source or destination was blank (unknown variable used?)" % dest)
                continue

            template_fh = open(template)
            template_data = template_fh.read()
            template_fh.close()

            buffer = self.templar.render(template_data, blended, None)
            results[dest] = buffer

            if write_file:
                self.logger.info("generating: %s" % dest)
                fd = open(dest, "w")
                fd.write(buffer)
                fd.close()

        return results
Example #8
0
    def write_pxe_file(self, filename, system, profile, distro, arch,
                       image=None, include_header=True, metadata=None, format="pxe"):
        """
        Write a configuration file for the boot loader(s).
        More system-specific configuration may come in later, if so
        that would appear inside the system object in api.py

        Can be used for different formats, "pxe" (default) and "grub".
        """
        if arch is None:
            raise "missing arch"

        if image and not os.path.exists(image.file):
            return None     # nfs:// URLs or something, can't use for TFTP

        if metadata is None:
            metadata = {}

        (rval, settings) = utils.input_string_or_dict(self.settings.to_dict())
        if rval:
            for key in settings.keys():
                metadata[key] = settings[key]
        # ---
        # just some random variables
        template = None
        buffer = ""

        # ---
        kickstart_path = None
        kernel_path = None
        initrd_path = None
        img_path = None

        if image is None:
            # not image based, it's something normalish

            img_path = os.path.join("/images", distro.name)

            if 'nexenta' == distro.breed:
                kernel_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'kernel', 'amd64', os.path.basename(distro.kernel))
                initrd_path = os.path.join("/images", distro.name, 'platform', 'i86pc', 'amd64', os.path.basename(distro.initrd))
            else:
                kernel_path = os.path.join("/images", distro.name, os.path.basename(distro.kernel))
                initrd_path = os.path.join("/images", distro.name, os.path.basename(distro.initrd))

            # Find the kickstart if we inherit from another profile
            if system:
                blended = utils.blender(self.api, True, system)
            else:
                blended = utils.blender(self.api, True, profile)
            kickstart_path = blended.get("kickstart", "")

            # update metadata with all known information
            # this allows for more powerful templating
            metadata.update(blended)

        else:
            # this is an image we are making available, not kernel+initrd
            if image.image_type == "direct":
                kernel_path = os.path.join("/images2", image.name)
            elif image.image_type == "memdisk":
                kernel_path = "/memdisk"
                initrd_path = os.path.join("/images2", image.name)
            else:
                # CD-ROM ISO or virt-clone image? We can't PXE boot it.
                kernel_path = None
                initrd_path = None

        if img_path is not None and "img_path" not in metadata:
            metadata["img_path"] = img_path
        if kernel_path is not None and "kernel_path" not in metadata:
            metadata["kernel_path"] = kernel_path
        if initrd_path is not None and "initrd_path" not in metadata:
            metadata["initrd_path"] = initrd_path

        # ---
        # choose a template
        if system:
            if format == "grub":
                if system.netboot_enabled:
                    template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubsystem.template")
                else:
                    local = os.path.join(self.settings.boot_loader_conf_template_dir, "grublocal.template")
                    if os.path.exists(local):
                        template = local
            else:   # pxe
                if system.netboot_enabled:
                    template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem.template")

                    if arch.startswith("ppc"):
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_ppc.template")
                    elif arch.startswith("arm"):
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_arm.template")
                    elif distro and distro.os_version.startswith("esxi"):
                        # ESXi uses a very different pxe method, using more files than
                        # a standard kickstart and different options - so giving it a dedicated
                        # PXE template makes more sense than shoe-horning it into the existing
                        # templates
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxesystem_esxi.template")
                else:
                    # local booting on ppc requires removing the system-specific dhcpd.conf filename
                    if arch is not None and arch.startswith("ppc"):
                        # Disable yaboot network booting for all interfaces on the system
                        for (name, interface) in system.interfaces.iteritems():

                            filename = "%s" % utils.get_config_filename(system, interface=name).lower()

                            # Remove symlink to the yaboot binary
                            f3 = os.path.join(self.bootloc, "ppc", filename)
                            if os.path.lexists(f3):
                                utils.rmfile(f3)

                            # Remove the interface-specific config file
                            f3 = os.path.join(self.bootloc, "etc", filename)
                            if os.path.lexists(f3):
                                utils.rmfile(f3)

                        # Yaboot/OF doesn't support booting locally once you've
                        # booted off the network, so nothing left to do
                        return None
                    else:
                        template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxelocal.template")
        else:
            # not a system record, so this is a profile record or an image
            if arch.startswith("arm"):
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_arm.template")
            elif format == "grub":
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "grubprofile.template")
            elif distro and distro.os_version.startswith("esxi"):
                # ESXi uses a very different pxe method, see comment above in the system section
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile_esxi.template")
            elif 'nexenta' == format:
                template = os.path.join(self.settings.boot_loader_conf_template_dir, 'nexenta_profile.template')
            else:
                template = os.path.join(self.settings.boot_loader_conf_template_dir, "pxeprofile.template")


        if kernel_path is not None:
            metadata["kernel_path"] = kernel_path
        if initrd_path is not None:
            metadata["initrd_path"] = initrd_path

        # generate the kernel options and append line:
        kernel_options = self.build_kernel_options(system, profile, distro,
                                                   image, arch, kickstart_path)
        metadata["kernel_options"] = kernel_options

        if distro and distro.os_version.startswith("esxi") and filename is not None:
            append_line = "BOOTIF=%s" % (os.path.basename(filename))
        elif "initrd_path" in metadata and (not arch or arch not in ["ppc", "ppc64", "arm"]):
            append_line = "append initrd=%s" % (metadata["initrd_path"])
        else:
            append_line = "append "
        append_line = "%s%s" % (append_line, kernel_options)
        if arch.startswith("ppc"):
            # remove the prefix "append"
            # TODO: this looks like it's removing more than append, really
            # not sure what's up here...
            append_line = append_line[7:]
        if distro and distro.os_version.startswith("xenserver620"):
            append_line = "%s" % (kernel_options)
        metadata["append_line"] = append_line

        # store variables for templating
        metadata["menu_label"] = ""
        if profile:
            if arch not in ["ppc", "ppc64"]:
                metadata["menu_label"] = "MENU LABEL %s" % profile.name
                metadata["profile_name"] = profile.name
        elif image:
            metadata["menu_label"] = "MENU LABEL %s" % image.name
            metadata["profile_name"] = image.name

        if system:
            metadata["system_name"] = system.name


        # get the template
        if kernel_path is not None:
            template_fh = open(template)
            template_data = template_fh.read()
            template_fh.close()
        else:
            # this is something we can't PXE boot
            template_data = "\n"

        # save file and/or return results, depending on how called.
        buffer = self.templar.render(template_data, metadata, None)
        if filename is not None:
            self.logger.info("generating: %s" % filename)
            fd = open(filename, "w")
            fd.write(buffer)
            fd.close()
        return buffer