예제 #1
0
    def validate_autoinstall_file(self, obj, is_profile):
        """
        Validate automatic installation file used by a system/profile

        @param Item obj system/profile
        @param bool is_profile if obj is a profile
        @return [bool, int, list] list with validation result, errors type and list of errors
        """

        last_errors = []
        blended = utils.blender(self.collection_mgr.api, False, obj)

        # get automatic installation template
        autoinstall = blended["autoinstall"]
        if autoinstall is None or autoinstall == "":
            self.logger.info("%s has no automatic installation template set, skipping" % obj.name)
            return [True, None, None]

        # generate automatic installation file
        os_version = blended["os_version"]
        self.logger.info("----------------------------")
        self.logger.debug("osversion: %s" % os_version)
        if is_profile:
            self.generate_autoinstall(profile=obj)
        else:
            self.generate_autoinstall(system=obj)
        last_errors = self.autoinstallgen.get_last_errors()
        if len(last_errors) > 0:
            return [False, TEMPLATING_ERROR, last_errors]
예제 #2
0
파일: netboot.py 프로젝트: holmesb/cobbler
    def _generate_netboot_system(self, system, cfglines: List[str],
                                 exclude_dns: bool):
        """
        Generates the ISOLINUX cfg configuration for any systems included in the image.
        :param system: The system which the configuration should be generated for.
        :param cfglines: The already existing lines of the configuration.
        :param exclude_dns: If DNS configuration should be excluded or not.
        """
        self.logger.info("processing system: %s", system.name)
        profile = system.get_conceptual_parent()
        dist = profile.get_conceptual_parent()
        distname = self.make_shorter(dist.name)
        self.copy_boot_files(dist, self.isolinuxdir, distname)

        cfglines.append("")
        cfglines.append("LABEL %s" % system.name)
        cfglines.append("  MENU LABEL %s" % system.name)
        cfglines.append("  kernel %s.krn" % distname)

        data = utils.blender(self.api, False, system)
        if not re.match(r"[a-z]+://.*", data["autoinstall"]):
            data[
                "autoinstall"] = "http://%s:%s/cblr/svc/op/autoinstall/system/%s" % (
                    data["server"],
                    data["http_port"],
                    system.name,
                )

        append_builder = AppendLineBuilder(distro_name=distname, data=data)
        append_line = append_builder.generate_system(dist, system, exclude_dns)
        cfglines.append(append_line)
예제 #3
0
    def validate_autoinstall_file(self, obj, is_profile: bool) -> list:
        """
        Validate automatic installation file used by a system/profile.

        :param obj: system/profile
        :param is_profile: if obj is a profile
        :returns: [bool, int, list] list with validation result, errors type and list of errors
        """

        last_errors = []
        blended = utils.blender(self.collection_mgr.api, False, obj)

        # get automatic installation template
        autoinstall = blended["autoinstall"]
        if autoinstall is None or autoinstall == "":
            self.logger.info(
                "%s has no automatic installation template set, skipping" %
                obj.name)
            return [True, 0, ()]

        # generate automatic installation file
        os_version = blended["os_version"]
        self.logger.info("----------------------------")
        self.logger.debug("osversion: %s" % os_version)
        if is_profile:
            self.generate_autoinstall(profile=obj)
        else:
            self.generate_autoinstall(system=obj)
        last_errors = self.autoinstallgen.get_last_errors()
        if len(last_errors) > 0:
            return [False, TEMPLATING_ERROR, last_errors]
        else:
            return [True, 0, ()]
예제 #4
0
    def test_generate_profile(self, api, create_kernel_initrd, fk_kernel,
                              fk_initrd, cleanup_items):
        # Arrange
        folder = create_kernel_initrd(fk_kernel, fk_initrd)
        kernel_path = os.path.join(folder, fk_kernel)
        initrd_path = os.path.join(folder, fk_initrd)
        test_distro = Distro(api)
        test_distro.name = "testdistro"
        test_distro.kernel = kernel_path
        test_distro.initrd = initrd_path
        api.add_distro(test_distro)
        test_profile = Profile(api)
        test_profile.name = "testprofile"
        test_profile.distro = test_distro.name
        api.add_profile(test_profile)
        blendered_data = utils.blender(api, False, test_profile)
        test_builder = AppendLineBuilder(test_distro.name, blendered_data)

        # Act
        result = test_builder.generate_profile("suse")

        # Assert
        # Very basic test yes but this is the expected result atm
        # TODO: Make tests more sophisticated
        assert (
            result ==
            " append initrd=testdistro.img install=http://127.0.0.1:80/cblr/links/testdistro autoyast=default.ks"
        )
예제 #5
0
def run(api, args, logger):
    settings = api.settings()

    for distro in api.distros():
        # collapse the object down to a rendered datastructure
        # the second argument set to false means we don't collapse hashes/arrays into a flat string
        target = utils.blender(api, False, distro)

        # Create metadata for the templar function
        # Right now, just using img_path, but adding more
        # cobbler variables here would probably be good
        metadata = {}
        metadata["img_path"] = os.path.join("/tftpboot/images", distro.name)

        # Create the templar instance
        templater = templar.Templar()

        # Loop through the hash of fetchable files,
        # executing a cp for each one
        for file in target["fetchable_files"].keys():
            file_dst = templater.render(file, metadata, None)
            try:
                shutil.copyfile(target["fetchable_files"][file], file_dst)
                api.log(
                    "copied file %s to %s for %s" %
                    (target["fetchable_files"][file], file_dst, distro.name))
            except:
                logger.error(
                    "failed to copy file %s to %s for %s" %
                    (target["fetchable_files"][file], file_dst, distro.name))
                return 1

    return 0
def run(api,args,logger):
   settings = api.settings()

   for distro in api.distros():
      # collapse the object down to a rendered datastructure
      # the second argument set to false means we don't collapse hashes/arrays into a flat string
      target = utils.blender(api, False, distro)

      # Create metadata for the templar function
      # Right now, just using img_path, but adding more
      # cobbler variables here would probably be good
      metadata = {}
      metadata["img_path"] = os.path.join("/tftpboot/images",distro.name)

      # Create the templar instance
      templater = templar.Templar()

      # Loop through the hash of fetchable files,
      # executing a cp for each one
      for file in target["fetchable_files"].keys():
        file_dst = templater.render(file,metadata,None)
        try:
          shutil.copyfile(target["fetchable_files"][file], file_dst)
          api.log("copied file %s to %s for %s" % (target["fetchable_files"][file],file_dst,distro.name))
        except:
          logger.error("failed to copy file %s to %s for %s" % (target["fetchable_files"][file],file_dst,distro.name))
          return 1

   return 0
예제 #7
0
파일: netboot.py 프로젝트: holmesb/cobbler
    def _generate_netboot_profile(self, profile, cfglines: List[str]):
        """
        Generates the ISOLINUX cfg configuration for any profiles included in the image.
        :param profile: The profile which the configuration should be generated for.
        :param cfglines: The already existing lines of the configuration.
        """
        self.logger.info('Processing profile: "%s"', profile.name)
        dist = profile.get_conceptual_parent()
        distname = self.make_shorter(dist.name)
        self.copy_boot_files(dist, self.isolinuxdir, distname)

        cfglines.append("")
        cfglines.append("LABEL %s" % profile.name)
        cfglines.append("  MENU LABEL %s" % profile.name)
        cfglines.append("  kernel %s.krn" % distname)

        data = utils.blender(self.api, False, profile)

        # SUSE is not using 'text'. Instead 'textmode' is used as kernel option.
        if dist is not None:
            utils.kopts_overwrite(data["kernel_options"],
                                  self.api.settings().server, dist.breed)

        if not re.match(r"[a-z]+://.*", data["autoinstall"]):
            data[
                "autoinstall"] = "http://%s:%s/cblr/svc/op/autoinstall/profile/%s" % (
                    data["server"],
                    data["http_port"],
                    profile.name,
                )

        append_builder = AppendLineBuilder(distro_name=distname, data=data)
        append_line = append_builder.generate_profile(dist.breed)
        cfglines.append(append_line)
예제 #8
0
    def generate_autoinstall(self, profile=None, system=None) -> str:
        """
        This is an internal method for generating an autoinstall config/script. Please use the
        ``generate_autoinstall_for_*`` methods. If you insist on using this mehtod please only supply a profile or a
        system, not both.

        :param profile: The profile to use for generating the autoinstall config/script.
        :param system: The system to use for generating the autoinstall config/script. If both arguments are given,
                       this wins.
        :return: The autoinstall script or configuration file as a string.
        """
        obj = system
        obj_type = "system"
        if system is None:
            obj = profile
            obj_type = "profile"

        meta = utils.blender(self.api, False, obj)
        autoinstall_rel_path = meta["autoinstall"]

        if not autoinstall_rel_path:
            return "# automatic installation file value missing or invalid at %s %s" % (obj_type, obj.name)

        # get parent distro
        distro = profile.get_conceptual_parent()
        if system is not None:
            distro = system.get_conceptual_parent().get_conceptual_parent()

        # make autoinstall_meta metavariable available at top level
        autoinstall_meta = meta["autoinstall_meta"]
        del meta["autoinstall_meta"]
        meta.update(autoinstall_meta)

        # add package repositories metadata to autoinstall metavariables
        if distro.breed == "redhat":
            meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None))
            meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None))
        # FIXME: implement something similar to zypper (SUSE based distros) and apt (Debian based distros)

        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])
        if "kernel_options_post" in meta:
            meta["kernel_options_post"] = utils.dict_to_string(meta["kernel_options_post"])

        # add install_source_directory metavariable to autoinstall metavariables if distro is based on Debian
        if distro.breed in ["debian", "ubuntu"] and "tree" in meta:
            urlparts = urllib.parse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            autoinstall_path = "%s/%s" % (self.settings.autoinstall_templates_dir, autoinstall_rel_path)
            raw_data = utils.read_file_contents(autoinstall_path)

            data = self.templar.render(raw_data, meta, None)

            return data
        except FileNotFoundError:
            error_msg = "automatic installation file %s not found at %s" \
                        % (meta["autoinstall"], self.settings.autoinstall_templates_dir)
            self.api.logger.warning(error_msg)
            return "# %s" % error_msg
예제 #9
0
    def generate_repo_stanza(self, obj, is_profile=True):

        """
        Automatically attaches yum repos to profiles/systems in automatic
        installation files (kickstart files) that contain the magic
        $yum_repo_stanza variable.  This includes repo objects as well as the
        yum repos that are part of split tree installs, whose data is stored
        with the distro (example: RHEL5 imports)
        """

        buf = ""
        blended = utils.blender(self.api, False, obj)
        repos = blended["repos"]

        # keep track of URLs and be sure to not include any duplicates
        included = {}

        for repo in repos:
            # see if this is a source_repo or not
            repo_obj = self.api.find_repo(repo)
            if repo_obj is not None:
                yumopts = ''
                for opt in repo_obj.yumopts:
                    # filter invalid values to the repo statement in automatic
                    # installation files
                    if not opt.lower() in validate.AUTOINSTALL_REPO_BLACKLIST:
                        yumopts = yumopts + " %s=%s" % (opt, repo_obj.yumopts[opt])
                if 'enabled' not in repo_obj.yumopts or repo_obj.yumopts['enabled'] == '1':
                    if repo_obj.mirror_locally:
                        baseurl = "http://%s/cobbler/repo_mirror/%s" % (blended["http_server"], repo_obj.name)
                        if baseurl not in included:
                            buf = buf + "repo --name=%s --baseurl=%s\n" % (repo_obj.name, baseurl)
                        included[baseurl] = 1
                    else:
                        if repo_obj.mirror not in included:
                            buf = buf + "repo --name=%s --baseurl=%s %s\n" % (repo_obj.name, repo_obj.mirror, yumopts)
                        included[repo_obj.mirror] = 1
            else:
                # FIXME: what to do if we can't find the repo object that is listed?
                # this should be a warning at another point, probably not here
                # so we'll just not list it so the automatic installation file
                # will still work as nothing will be here to read the output noise.
                # Logging might be useful.
                pass

        if is_profile:
            distro = obj.get_conceptual_parent()
        else:
            distro = obj.get_conceptual_parent().get_conceptual_parent()

        source_repos = distro.source_repos
        count = 0
        for x in source_repos:
            count = count + 1
            if not x[1] in included:
                buf = buf + "repo --name=source-%s --baseurl=%s\n" % (count, x[1])
                included[x[1]] = 1

        return buf
예제 #10
0
    def generate_autoinstall(self, profile=None, system=None):

        obj = system
        obj_type = "system"
        if system is None:
            obj = profile
            obj_type = "profile"

        meta = utils.blender(self.api, False, obj)
        autoinstall_rel_path = meta["autoinstall"]

        if not autoinstall_rel_path:
            return "# automatic installation file value missing or invalid at %s %s" % (
                obj_type, obj.name)

        # get parent distro
        distro = profile.get_conceptual_parent()
        if system is not None:
            distro = system.get_conceptual_parent().get_conceptual_parent()

        # make autoinstall_meta metavariable available at top level
        autoinstall_meta = meta["autoinstall_meta"]
        del meta["autoinstall_meta"]
        meta.update(autoinstall_meta)

        # add package repositories metadata to autoinstall metavariables
        if distro.breed == "redhat":
            meta["yum_repo_stanza"] = self.generate_repo_stanza(
                obj, (system is None))
            meta["yum_config_stanza"] = self.generate_config_stanza(
                obj, (system is None))
        # FIXME: implement something similar to zypper (SUSE based distros) and apt
        #        (Debian based distros)

        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])
        if "kernel_options_post" in meta:
            meta["kernel_options_post"] = utils.dict_to_string(
                meta["kernel_options_post"])

        # add install_source_directory metavariable to autoinstall metavariables
        # if distro is based on Debian
        if distro.breed in ["debian", "ubuntu"] and "tree" in meta:
            urlparts = urllib.parse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            autoinstall_path = "%s/%s" % (
                self.settings.autoinstall_templates_dir, autoinstall_rel_path)
            raw_data = utils.read_file_contents(autoinstall_path,
                                                self.api.logger)

            data = self.templar.render(raw_data, meta, None, obj)

            return data
        except FileNotFoundException:
            error_msg = "automatic installation file %s not found at %s" % (
                meta["autoinstall"], self.settings.autoinstall_templates_dir)
            self.api.logger.warning(error_msg)
            return "# %s" % error_msg
예제 #11
0
def run(api, args, logger):
    """
    This method runs the trigger, meaning in this case that old puppet certs are automatically removed via puppetca.

    The list of args should have two elements:
        - 0: system or profile
        - 1: the name of the system or profile

    :param api: The api to resolve external information with.
    :param args: Already described above.
    :param logger: The logger to audit the action with.
    :return: "0" on success. If unsuccessful this raises an exception.
    """
    objtype = args[0]
    name = args[1]

    if objtype != "system":
        return 0

    settings = api.settings()

    if not str(
            settings.puppet_auto_setup).lower() in ["1", "yes", "y", "true"]:
        return 0

    if not str(settings.remove_old_puppet_certs_automatically).lower() in [
            "1", "yes", "y", "true"
    ]:
        return 0

    system = api.find_system(name)
    system = utils.blender(api, False, system)
    hostname = system["hostname"]
    if not re.match(r'[\w-]+\..+', hostname):
        search_domains = system['name_servers_search']
        if search_domains:
            hostname += '.' + search_domains[0]
    if not re.match(r'[\w-]+\..+', hostname):
        default_search_domains = system['default_name_servers_search']
        if default_search_domains:
            hostname += '.' + default_search_domains[0]
    puppetca_path = settings.puppetca_path
    cmd = [puppetca_path, 'cert', 'clean', hostname]

    rc = 0

    try:
        rc = utils.subprocess_call(logger, cmd, shell=False)
    except:
        if logger is not None:
            logger.warning("failed to execute %s" % puppetca_path)

    if rc != 0:
        if logger is not None:
            logger.warning("puppet cert removal for %s failed" % name)

    return 0
예제 #12
0
    def createrepo_walker(self, repo, dirname, fnames):
        """
        Used to run createrepo on a copied Yum mirror.

        :param repo: The repository object to run for.
        :param dirname: The directory to run in.
        :param fnames: Not known what this is for.
        """
        if os.path.exists(dirname) or repo['breed'] == 'rsync':
            utils.remove_yum_olddata(dirname)

            # add any repo metadata we can use
            mdoptions = []
            if os.path.isfile("%s/.origin/repodata/repomd.xml" % (dirname)):
                if HAS_LIBREPO:
                    rd = self.librepo_getinfo("%s/.origin" % (dirname))
                elif HAS_YUM:
                    rmd = yum.repoMDObject.RepoMD(
                        '', "%s/.origin/repodata/repomd.xml" % (dirname))
                    rd = rmd.repoData
                else:
                    utils.die(self.logger,
                              "yum/librepo is required to use this feature")

                if "group" in rd:
                    if HAS_LIBREPO:
                        groupmdfile = rd['group']['location_href']
                    else:
                        groupmdfile = rmd.getData("group").location[1]
                    mdoptions.append("-g %s" % groupmdfile)
                if "prestodelta" in rd:
                    # need createrepo >= 0.9.7 to add deltas
                    if utils.get_family() in ("redhat", "suse"):
                        cmd = "/usr/bin/rpmquery --queryformat=%{VERSION} createrepo"
                        createrepo_ver = utils.subprocess_get(self.logger, cmd)
                        if not createrepo_ver[0:1].isdigit():
                            cmd = "/usr/bin/rpmquery --queryformat=%{VERSION} createrepo_c"
                            createrepo_ver = utils.subprocess_get(
                                self.logger, cmd)
                        if utils.compare_versions_gt(createrepo_ver, "0.9.7"):
                            mdoptions.append("--deltas")
                        else:
                            self.logger.error(
                                "this repo has presto metadata; you must upgrade createrepo to >= 0.9.7 first and then need to resync the repo through Cobbler."
                            )

            blended = utils.blender(self.api, False, repo)
            flags = blended.get("createrepo_flags", "(ERROR: FLAGS)")
            try:
                cmd = "createrepo %s %s %s" % (" ".join(mdoptions), flags,
                                               pipes.quote(dirname))
                utils.subprocess_call(self.logger, cmd)
            except:
                utils.log_exc(self.logger)
                self.logger.error("createrepo failed.")
            del fnames[:]  # we're in the right place
예제 #13
0
    def generate_autoinstall(self, profile=None, system=None):

        obj = system
        obj_type = "system"
        if system is None:
            obj = profile
            obj_type = "profile"

        meta = utils.blender(self.api, False, obj)
        autoinstall_rel_path = meta["autoinstall"]

        if not autoinstall_rel_path:
            return "# automatic installation file value missing or invalid at %s %s" % (obj_type, obj.name)

        # get parent distro
        distro = profile.get_conceptual_parent()
        if system is not None:
            distro = system.get_conceptual_parent().get_conceptual_parent()

        # make autoinstall_meta metavariable available at top level
        autoinstall_meta = meta["autoinstall_meta"]
        del meta["autoinstall_meta"]
        meta.update(autoinstall_meta)

        # add package repositories metadata to autoinstall metavariables
        if distro.breed == "redhat":
            meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None))
            meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None))
        # FIXME: implement something similar to zypper (SUSE based distros) and apt
        #        (Debian based distros)

        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])
        if "kernel_options_post" in meta:
            meta["kernel_options_post"] = utils.dict_to_string(meta["kernel_options_post"])

        # add install_source_directory metavariable to autoinstall metavariables
        # if distro is based on Debian
        if distro.breed in ["debian", "ubuntu"] and "tree" in meta:
            urlparts = urlparse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            autoinstall_path = "%s/%s" % (self.settings.autoinstall_templates_dir, autoinstall_rel_path)
            raw_data = utils.read_file_contents(autoinstall_path, self.api.logger)

            data = self.templar.render(raw_data, meta, None, obj)

            if distro.breed == "suse":
                # AutoYaST profile
                data = self.generate_autoyast(profile, system, data)

            return data
        except FileNotFoundException:
            error_msg = "automatic installation file %s not found at %s" % (meta["autoinstall"], self.settings.autoinstall_templates_dir)
            self.api.logger.warning(error_msg)
            return "# %s" % error_msg
예제 #14
0
def test_blender():
    # Arrange
    test_api = CobblerAPI()
    root_item = Distro(test_api)

    # Act
    result = utils.blender(test_api, False, root_item)

    # Assert
    assert len(result) == 147
    assert "server" in result
    assert "os_version" in result
예제 #15
0
파일: item.py 프로젝트: openSUSE/cobbler
    def dump_vars(self, formatted_output: bool = True):
        """
        Dump all variables.

        :param formatted_output: Whether to format the output or not.
        :return: The raw or formatted data.
        """
        raw = utils.blender(self.api, False, self)
        if formatted_output:
            return pprint.pformat(raw)
        else:
            return raw
예제 #16
0
def test_blender():
    # Arrange
    # TODO: Create some objects
    api = CobblerAPI()
    root_item = None
    expected = {}

    # Act
    result = utils.blender(api, False, root_item)

    # Assert
    assert expected == result
예제 #17
0
파일: tftpgen.py 프로젝트: lucap22/cobbler
    def generate_bootcfg(self, what, name):
        if what.lower() not in ("profile", "system"):
            return "# bootcfg is only valid for profiles and systems"

        distro = None
        if what == "profile":
            obj = self.api.find_profile(name=name)
            distro = obj.get_conceptual_parent()
        else:
            obj = self.api.find_system(name=name)
            distro = obj.get_conceptual_parent().get_conceptual_parent()

        # For multi-arch distros, the distro name in distro_mirror
        # may not contain the arch string, so we need to figure out
        # the path based on where the kernel is stored. We do this
        # because some distros base future downloads on the initial
        # URL passed in, so all of the files need to be at this location
        # (which is why we can't use the images link, which just contains
        # the kernel and initrd).
        distro_mirror_name = string.join(distro.kernel.split('/')[-2:-1], '')

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

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

        blended['distro'] = distro_mirror_name

        # FIXME: img_path should probably be moved up into the
        #        blender function to ensure they're consistently
        #        available to templates across the board
        if obj.enable_gpxe:
            blended['img_path'] = 'http://%s:%s/cobbler/links/%s' % (
                self.settings.server, self.settings.http_port, distro.name)
        else:
            blended['img_path'] = os.path.join("/images", distro.name)

        template = os.path.join(
            self.settings.boot_loader_conf_template_dir,
            "bootcfg_%s_%s.template" % (what.lower(), distro.os_version))
        if not os.path.exists(template):
            return "# boot.cfg template not found for the %s named %s (filename=%s)" % (
                what, name, template)

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

        return self.templar.render(template_data, blended, None)
예제 #18
0
    def get_yum_config(self, obj, is_profile):
        """
        Return one large yum repo config blob suitable for use by any target system that requests it.

        :param obj: The object to generate the yumconfig for.
        :param is_profile: If the requested object is a profile. (Parameter not used currently)
        :type is_profile: bool
        :return: The generated yumconfig or the errors.
        :rtype: str
        """

        totalbuf = ""

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

        input_files = []

        # Tack on all the install source repos IF there is more than one. This is basically to support things like
        # RHEL5 split trees if there is only one, then there is no need to do this.

        included = {}
        for r in blended["source_repos"]:
            filename = self.settings.webdir + "/" + "/".join(
                r[0].split("/")[4:])
            if filename not in included:
                input_files.append(filename)
            included[filename] = 1

        for repo in blended["repos"]:
            path = os.path.join(self.settings.webdir, "repo_mirror", repo,
                                "config.repo")
            if path not in included:
                input_files.append(path)
            included[path] = 1

        for infile in input_files:
            try:
                infile_h = open(infile)
            except:
                # File does not exist and the user needs to run reposync before we will use this, Cobbler check will
                # mention this problem
                totalbuf += "\n# error: could not read repo source: %s\n\n" % infile
                continue

            infile_data = infile_h.read()
            infile_h.close()
            outfile = None  # disk output only
            totalbuf += self.templar.render(infile_data, blended, outfile,
                                            None)
            totalbuf += "\n\n"

        return totalbuf
예제 #19
0
파일: item.py 프로젝트: y2kenny/cobbler
    def dump_vars(self, data, format=True):
        """
        Dump all variables.

        :param data: Unused parameter in this method.
        :param format: Whether to format the output or not.
        :return: The raw or formatted data.
        """
        raw = utils.blender(self.collection_mgr.api, False, self)
        if format:
            return pprint.pformat(raw)
        else:
            return raw
예제 #20
0
def run(api, args, logger):
    """
    The obligatory Cobbler modules hook.

    :param api: The api to resolve all information with.
    :param args: This is an array with two items. The first may be ``system`` or ``profile`` and the second is the name
                 of this system or profile.
    :param logger: The logger to audit all actions with.
    :return: ``0`` or nothing.
    """
    objtype = args[0]
    name = args[1]
    # ip = args[2]          # ip or "?"

    if objtype != "system":
        return 0

    settings = api.settings()

    if not str(
            settings.puppet_auto_setup).lower() in ["1", "yes", "y", "true"]:
        return 0

    if not str(settings.sign_puppet_certs_automatically).lower() in [
            "1", "yes", "y", "true"
    ]:
        return 0

    system = api.find_system(name)
    system = utils.blender(api, False, system)
    hostname = system["hostname"]
    if not re.match(r'[\w-]+\..+', hostname):
        search_domains = system['name_servers_search']
        if search_domains:
            hostname += '.' + search_domains[0]
    puppetca_path = settings.puppetca_path
    cmd = [puppetca_path, 'cert', 'sign', hostname]

    rc = 0

    try:
        rc = utils.subprocess_call(logger, cmd, shell=False)
    except:
        if logger is not None:
            logger.warning("failed to execute %s" % puppetca_path)

    if rc != 0:
        if logger is not None:
            logger.warning("signing of puppet cert for %s failed" % name)

    return 0
예제 #21
0
    def createrepo_walker(self, repo, dirname: str, fnames):
        """
        Used to run createrepo on a copied Yum mirror.

        :param repo: The repository object to run for.
        :param dirname: The directory to run in.
        :param fnames: Not known what this is for.
        """
        if os.path.exists(dirname) or repo.breed == RepoBreeds.RSYNC:
            utils.remove_yum_olddata(dirname)

            # add any repo metadata we can use
            mdoptions = []
            origin_path = os.path.join(dirname, ".origin")
            repodata_path = os.path.join(origin_path, "repodata")

            if os.path.isfile(os.path.join(repodata_path, "repomd.xml")):
                rd = self.librepo_getinfo(origin_path)

                if "group" in rd:
                    groupmdfile = rd['group']['location_href']
                    mdoptions.append("-g %s" %
                                     os.path.join(origin_path, groupmdfile))
                if "prestodelta" in rd:
                    # need createrepo >= 0.9.7 to add deltas
                    if utils.get_family() in ("redhat", "suse"):
                        cmd = "/usr/bin/rpmquery --queryformat=%{VERSION} createrepo"
                        createrepo_ver = utils.subprocess_get(cmd)
                        if not createrepo_ver[0:1].isdigit():
                            cmd = "/usr/bin/rpmquery --queryformat=%{VERSION} createrepo_c"
                            createrepo_ver = utils.subprocess_get(cmd)
                        if utils.compare_versions_gt(createrepo_ver, "0.9.7"):
                            mdoptions.append("--deltas")
                        else:
                            self.logger.error(
                                "this repo has presto metadata; you must upgrade createrepo to >= 0.9.7 "
                                "first and then need to resync the repo through Cobbler."
                            )

            blended = utils.blender(self.api, False, repo)
            flags = blended.get("createrepo_flags", "(ERROR: FLAGS)")
            try:
                cmd = "createrepo %s %s %s" % (" ".join(mdoptions), flags,
                                               pipes.quote(dirname))
                utils.subprocess_call(cmd)
            except:
                utils.log_exc()
                self.logger.error("createrepo failed.")
            del fnames[:]  # we're in the right place
예제 #22
0
    def generate_kickstart(self, profile=None, system=None):

        obj = system
        if system is None:
            obj = profile

        meta = utils.blender(self.api, False, obj)
        kickstart_path = meta["kickstart"]

        if not kickstart_path:
            return "# kickstart is missing or invalid: %s" % meta["kickstart"]

        ksmeta = meta["ks_meta"]
        del meta["ks_meta"]
        meta.update(ksmeta)  # make available at top level
        meta["yum_repo_stanza"] = self.generate_repo_stanza(
            obj, (system is None))
        meta["yum_config_stanza"] = self.generate_config_stanza(
            obj, (system is None))
        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])

        # add extra variables for other distro types
        if "tree" in meta:
            urlparts = urlparse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            raw_data = utils.read_file_contents(kickstart_path,
                                                self.api.logger)
            if raw_data is None:
                return "# kickstart is sourced externally: %s" % meta[
                    "kickstart"]
            distro = profile.get_conceptual_parent()
            if system is not None:
                distro = system.get_conceptual_parent().get_conceptual_parent()

            data = self.templar.render(raw_data, meta, None, obj)

            if distro.breed == "suse":
                # AutoYaST profile
                data = self.generate_autoyast(profile, system, data)

            return data
        except FileNotFoundException:
            self.api.logger.warning("kickstart not found: %s" %
                                    meta["kickstart"])
            return "# kickstart not found: %s" % meta["kickstart"]
예제 #23
0
    def generate_config_stanza(self, obj, is_profile=True):

        """
        Add in automatic to configure /etc/yum.repos.d on the remote system
        if the kickstart file contains the magic $yum_config_stanza.
        """

        if not self.settings.yum_post_install_mirror:
            return ""

        blended = utils.blender(self.api, False, obj)
        if is_profile:
            url = "http://%s/cblr/svc/op/yum/profile/%s" % (blended["http_server"], obj.name)
        else:
            url = "http://%s/cblr/svc/op/yum/system/%s" % (blended["http_server"], obj.name)

        return "wget \"%s\" --output-document=/etc/yum.repos.d/cobbler-config.repo\n" % (url)
예제 #24
0
def run(api, args, logger):
    objtype = args[0]  # "system" or "profile"
    name = args[1]  # name of system or profile
    # ip = args[2]      # ip or "?"

    if objtype != "system":
        return 0

    settings = api.settings()

    if not str(
            settings.puppet_auto_setup).lower() in ["1", "yes", "y", "true"]:
        return 0

    if not str(settings.remove_old_puppet_certs_automatically).lower() in [
            "1", "yes", "y", "true"
    ]:
        return 0

    system = api.find_system(name)
    system = utils.blender(api, False, system)
    hostname = system["hostname"]
    if not re.match(r'[\w-]+\..+', hostname):
        search_domains = system['name_servers_search']
        if search_domains:
            hostname += '.' + search_domains[0]
    if not re.match(r'[\w-]+\..+', hostname):
        default_search_domains = system['default_name_servers_search']
        if default_search_domains:
            hostname += '.' + default_search_domains[0]
    puppetca_path = settings.puppetca_path
    cmd = [puppetca_path, 'cert', 'clean', hostname]

    rc = 0

    try:
        rc = utils.subprocess_call(logger, cmd, shell=False)
    except:
        if logger is not None:
            logger.warning("failed to execute %s" % puppetca_path)

    if rc != 0:
        if logger is not None:
            logger.warning("puppet cert removal for %s failed" % name)

    return 0
예제 #25
0
    def generate_config_stanza(self, obj, is_profile=True):

        """
        Add in automatic to configure /etc/yum.repos.d on the remote system
        if the automatic installation file (kickstart file) contains the magic
        $yum_config_stanza.
        """

        if not self.settings.yum_post_install_mirror:
            return ""

        blended = utils.blender(self.api, False, obj)
        if is_profile:
            url = "http://%s/cblr/svc/op/yum/profile/%s" % (blended["http_server"], obj.name)
        else:
            url = "http://%s/cblr/svc/op/yum/system/%s" % (blended["http_server"], obj.name)

        return "curl \"%s\" --output /etc/yum.repos.d/cobbler-config.repo\n" % (url)
예제 #26
0
    def write_boot_files_distro(self, distro):
        # Collapse the object down to a rendered datastructure.
        # The second argument set to false means we don't collapse dicts/arrays into a flat string.
        target = utils.blender(self.api, False, distro)

        # Create metadata for the templar function.
        # Right now, just using local_img_path, but adding more Cobbler variables here would probably be good.
        metadata = {}
        metadata["local_img_path"] = os.path.join(self.bootloc, "images",
                                                  distro.name)
        metadata["web_img_path"] = os.path.join(self.webdir, "distro_mirror",
                                                distro.name)
        # Create the templar instance.  Used to template the target directory
        templater = templar.Templar(self.collection_mgr)

        # Loop through the dict of boot files, executing a cp for each one
        self.logger.info("processing boot_files for distro: %s" % distro.name)
        for boot_file in list(target["boot_files"].keys()):
            rendered_target_file = templater.render(boot_file, metadata, None)
            rendered_source_file = templater.render(
                target["boot_files"][boot_file], metadata, None)
            try:
                for file in glob.glob(rendered_source_file):
                    if file == rendered_source_file:
                        # this wasn't really a glob, so just copy it as is
                        filedst = rendered_target_file
                    else:
                        # this was a glob, so figure out what the destination file path/name should be
                        tgt_path, tgt_file = os.path.split(file)
                        rnd_path, rnd_file = os.path.split(
                            rendered_target_file)
                        filedst = os.path.join(rnd_path, tgt_file)

                        if not os.path.isdir(rnd_path):
                            utils.mkdir(rnd_path)
                    if not os.path.isfile(filedst):
                        shutil.copyfile(file, filedst)
                    self.collection_mgr.api.log("copied file %s to %s for %s" %
                                                (file, filedst, distro.name))
            except:
                self.logger.error("failed to copy file %s to %s for %s", file,
                                  filedst, distro.name)

        return 0
예제 #27
0
def run(api, args) -> int:
    """
    The obligatory Cobbler modules hook.

    :param api: The api to resolve all information with.
    :param args: This is an array with two items. The first must be ``system``, if the value is different we do an
                 early and the second is the name of this system or profile.
    :return: ``0`` or nothing.
    """
    objtype = args[0]
    name = args[1]

    if objtype != "system":
        return 0

    settings = api.settings()

    if not settings.puppet_auto_setup:
        return 0

    if not settings.sign_puppet_certs_automatically:
        return 0

    system = api.find_system(name)
    system = utils.blender(api, False, system)
    hostname = system["hostname"]
    if not re.match(r"[\w-]+\..+", hostname):
        search_domains = system["name_servers_search"]
        if search_domains:
            hostname += "." + search_domains[0]
    puppetca_path = settings.puppetca_path
    cmd = [puppetca_path, "cert", "sign", hostname]

    rc = 0

    try:
        rc = utils.subprocess_call(cmd, shell=False)
    except:
        logger.warning("failed to execute %s", puppetca_path)

    if rc != 0:
        logger.warning("signing of puppet cert for %s failed", name)

    return 0
예제 #28
0
    def generate_autoinstall(self, profile=None, system=None):

        obj = system
        obj_type = "system"
        if system is None:
            obj = profile
            obj_type = "profile"

        meta = utils.blender(self.api, False, obj)
        autoinstall_rel_path = meta["autoinstall"]

        if not autoinstall_rel_path:
            return "# automatic installation file value missing or invalid at %s %s" % (obj_type, obj.name)

        autoinstall_meta = meta["autoinstall_meta"]
        del meta["autoinstall_meta"]
        meta.update(autoinstall_meta)     # make available at top level
        meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None))
        meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None))
        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])

        # add extra variables for other distro types
        if "tree" in meta:
            urlparts = urlparse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            autoinstall_path = "%s/%s" % (self.settings.autoinstall_templates_dir, autoinstall_rel_path)
            raw_data = utils.read_file_contents(autoinstall_path, self.api.logger)
            distro = profile.get_conceptual_parent()
            if system is not None:
                distro = system.get_conceptual_parent().get_conceptual_parent()

            data = self.templar.render(raw_data, meta, None, obj)

            if distro.breed == "suse":
                # AutoYaST profile
                data = self.generate_autoyast(profile, system, data)

            return data
        except FileNotFoundException:
            error_msg = "automatic installation file %s not found at %s" % (meta["autoinstall"], self.settings.autoinstall_templates_dir)
            self.api.logger.warning(error_msg)
            return "# %s" % error_msg
예제 #29
0
def run(api, args, logger):
    objtype = args[0]   # "system" or "profile"
    name = args[1]      # name of system or profile
    # ip = args[2]      # ip or "?"

    if objtype != "system":
        return 0

    settings = api.settings()

    if not str(settings.puppet_auto_setup).lower() in ["1", "yes", "y", "true"]:
        return 0

    if not str(settings.remove_old_puppet_certs_automatically).lower() in ["1", "yes", "y", "true"]:
        return 0

    system = api.find_system(name)
    system = utils.blender(api, False, system)
    hostname = system["hostname"]
    if not re.match(r'[\w-]+\..+', hostname):
        search_domains = system['name_servers_search']
        if search_domains:
            hostname += '.' + search_domains[0]
    if not re.match(r'[\w-]+\..+', hostname):
        default_search_domains = system['default_name_servers_search']
        if default_search_domains:
            hostname += '.' + default_search_domains[0]
    puppetca_path = settings.puppetca_path
    cmd = [puppetca_path, 'cert', 'clean', hostname]

    rc = 0

    try:
        rc = utils.subprocess_call(logger, cmd, shell=False)
    except:
        if logger is not None:
            logger.warning("failed to execute %s" % puppetca_path)

    if rc != 0:
        if logger is not None:
            logger.warning("puppet cert removal for %s failed" % name)

    return 0
예제 #30
0
    def _generate_descendant(
        self,
        descendant,
        cfglines: List[str],
        distro,
        airgapped: bool,
        repo_names_to_copy: dict,
    ):
        """
        Generate the ISOLINUX cfg configuration file for the descendant.
        :param descendant: The descendant to generate the config file for. Must be a profile or system object.
        :param cfglines: The content of the file which has already been generated.
        :param distro: The parent distro.
        :param airgapped: Whether the generated ISO should be bootable in an airgapped environment or not.
        :param repo_names_to_copy: The repository names to copy in the case of an airgapped environment.
        """
        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.api.settings().server, distro.breed)

        cfglines.append("")
        cfglines.append("LABEL %s" % descendant.name)
        if menu_indent:
            cfglines.append("  MENU INDENT %d" % menu_indent)
        cfglines.append("  MENU LABEL %s" % descendant.name)
        cfglines.append("  kernel %s" % os.path.basename(distro.kernel))

        cfglines.append(
            _generate_append_line_standalone(data, distro, descendant))

        autoinstall_data = self._generate_autoinstall_data(
            descendant, distro, airgapped, data, repo_names_to_copy)
        autoinstall_name = os.path.join(self.isolinuxdir,
                                        "%s.cfg" % descendant.name)
        with open(autoinstall_name, "w+") as autoinstall_file:
            autoinstall_file.write(autoinstall_data)
예제 #31
0
    def generate_kickstart(self, profile=None, system=None):

        obj = system
        if system is None:
            obj = profile

        meta = utils.blender(self.api, False, obj)
        kickstart_path = meta["kickstart"]

        if not kickstart_path:
            return "# kickstart is missing or invalid: %s" % meta["kickstart"]

        ksmeta = meta["ks_meta"]
        del meta["ks_meta"]
        meta.update(ksmeta)     # make available at top level
        meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None))
        meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None))
        meta["kernel_options"] = utils.dict_to_string(meta["kernel_options"])

        # add extra variables for other distro types
        if "tree" in meta:
            urlparts = urlparse.urlsplit(meta["tree"])
            meta["install_source_directory"] = urlparts[2]

        try:
            raw_data = utils.read_file_contents(kickstart_path, self.api.logger)
            if raw_data is None:
                return "# kickstart is sourced externally: %s" % meta["kickstart"]
            distro = profile.get_conceptual_parent()
            if system is not None:
                distro = system.get_conceptual_parent().get_conceptual_parent()

            data = self.templar.render(raw_data, meta, None, obj)

            if distro.breed == "suse":
                # AutoYaST profile
                data = self.generate_autoyast(profile, system, data)

            return data
        except FileNotFoundException:
            self.api.logger.warning("kickstart not found: %s" % meta["kickstart"])
            return "# kickstart not found: %s" % meta["kickstart"]
예제 #32
0
    def generate_config_stanza(self, obj, is_profile: bool = True):
        """
        Add in automatic to configure /etc/yum.repos.d on the remote system if the automatic installation file
        (template file) contains the magic $yum_config_stanza.

        :param obj: The profile or system to generate a generate a config stanza for.
        :param is_profile: If the object is a profile. If False it is assumed that the object is a system.
        :return: The curl command to execute to get the configuration for a system or profile.
        """

        if not self.settings.yum_post_install_mirror:
            return ""

        blended = utils.blender(self.api, False, obj)
        if is_profile:
            url = "http://%s/cblr/svc/op/yum/profile/%s" % (blended["http_server"], obj.name)
        else:
            url = "http://%s/cblr/svc/op/yum/system/%s" % (blended["http_server"], obj.name)

        return "curl \"%s\" --output /etc/yum.repos.d/cobbler-config.repo\n" % (url)
예제 #33
0
파일: tftpgen.py 프로젝트: lucap22/cobbler
    def generate_script(self, what, objname, script_name):
        if what == "profile":
            obj = self.api.find_profile(name=objname)
        else:
            obj = self.api.find_system(name=objname)

        if not obj:
            return "# %s named %s not found" % (what, objname)

        distro = obj.get_conceptual_parent()
        while distro.get_conceptual_parent():
            distro = distro.get_conceptual_parent()

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

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

        # FIXME: img_path should probably be moved up into the
        #        blender function to ensure they're consistently
        #        available to templates across the board
        if obj.enable_gpxe:
            blended['img_path'] = 'http://%s:%s/cobbler/links/%s' % (
                self.settings.server, self.settings.http_port, distro.name)
        else:
            blended['img_path'] = os.path.join("/images", distro.name)

        template = os.path.normpath(
            os.path.join("/var/lib/cobbler/autoinstall_scripts", script_name))
        if not os.path.exists(template):
            return "# script template %s not found" % script_name

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

        return self.templar.render(template_data, blended, None, obj)
예제 #34
0
    def write_boot_files_distro(self, distro):
        # collapse the object down to a rendered datastructure
        # the second argument set to false means we don't collapse
        # dicts/arrays into a flat string
        target = utils.blender(self.collection_mgr.api, False, distro)

        # Create metadata for the templar function
        # Right now, just using local_img_path, but adding more
        # cobbler variables here would probably be good
        metadata = {}
        metadata["local_img_path"] = os.path.join(utils.tftpboot_location(), "images", distro.name)
        # Create the templar instance.  Used to template the target directory
        templater = templar.Templar(self.collection_mgr)

        # Loop through the dict of boot files,
        # executing a cp for each one
        self.logger.info("processing boot_files for distro: %s" % distro.name)
        for file in list(target["boot_files"].keys()):
            rendered_file = templater.render(file, metadata, None)
            try:
                for f in glob.glob(target["boot_files"][file]):
                    if f == target["boot_files"][file]:
                        # this wasn't really a glob, so just copy it as is
                        filedst = rendered_file
                    else:
                        # this was a glob, so figure out what the destination
                        # file path/name should be
                        tgt_path, tgt_file = os.path.split(f)
                        rnd_path, rnd_file = os.path.split(rendered_file)
                        filedst = os.path.join(rnd_path, tgt_file)
                    if not os.path.isfile(filedst):
                        shutil.copyfile(f, filedst)
                    self.collection_mgr.api.log("copied file %s to %s for %s" % (f, filedst, distro.name))
            except:
                self.logger.error("failed to copy file %s to %s for %s" % (f, filedst, distro.name))

        return 0
예제 #35
0
파일: isc.py 프로젝트: vzhestkov/cobbler
    def write_configs(self):
        """
        DHCP files are written when ``manage_dhcp`` is set in our settings.
        """

        template_file = "/etc/cobbler/dhcp.template"
        blender_cache = {}

        try:
            f2 = open(template_file, "r")

        except Exception:
            raise CX("error reading template: %s" % template_file)

        template_data = ""
        template_data = f2.read()
        f2.close()

        # Use a simple counter for generating generic names where a hostname is not available.
        counter = 0

        # We used to just loop through each system, but now we must loop through each network interface of each system.
        dhcp_tags = {"default": {}}
        yaboot = "/yaboot"

        # FIXME: ding should evolve into the new dhcp_tags dict
        ding = {}
        ignore_macs = []

        for system in self.systems:
            if not system.is_management_supported(cidr_ok=False):
                continue

            profile = system.get_conceptual_parent()
            distro = profile.get_conceptual_parent()

            # if distro is None then the profile is really an image record
            for (name, system_interface) in list(system.interfaces.items()):

                # We make a copy because we may modify it before adding it to the dhcp_tags and we don't want to affect
                # the master copy.
                interface = copy.deepcopy(system_interface)

                if interface["if_gateway"]:
                    interface["gateway"] = interface["if_gateway"]
                else:
                    interface["gateway"] = system.gateway

                mac = interface["mac_address"]

                if interface["interface_type"] in ("bond_slave", "bridge_slave", "bonded_bridge_slave"):

                    if interface["interface_master"] not in system.interfaces:
                        # Can't write DHCP entry; master interface does not exist
                        continue

                    # We may have multiple bonded interfaces, so we need a composite index into ding.
                    name_master = "%s-%s" % (system.name, interface["interface_master"])
                    if name_master not in ding:
                        ding[name_master] = {interface["interface_master"]: []}

                    if len(ding[name_master][interface["interface_master"]]) == 0:
                        ding[name_master][interface["interface_master"]].append(mac)
                    else:
                        ignore_macs.append(mac)

                    ip = system.interfaces[interface["interface_master"]]["ip_address"]
                    netmask = system.interfaces[interface["interface_master"]]["netmask"]
                    dhcp_tag = system.interfaces[interface["interface_master"]]["dhcp_tag"]
                    host = system.interfaces[interface["interface_master"]]["dns_name"]

                    if ip is None or ip == "":
                        for (nam2, int2) in list(system.interfaces.items()):
                            if nam2.startswith(interface["interface_master"] + ".") \
                                    and int2["ip_address"] is not None \
                                    and int2["ip_address"] != "":
                                ip = int2["ip_address"]
                                break

                    interface["ip_address"] = ip
                    interface["netmask"] = netmask
                else:
                    ip = interface["ip_address"]
                    netmask = interface["netmask"]
                    dhcp_tag = interface["dhcp_tag"]
                    host = interface["dns_name"]

                if distro is not None:
                    interface["distro"] = distro.to_dict()

                if mac is None or mac == "":
                    # can't write a DHCP entry for this system
                    continue

                counter = counter + 1

                # the label the entry after the hostname if possible
                if host is not None and host != "":
                    if name != "eth0":
                        interface["name"] = "%s-%s" % (host, name)
                    else:
                        interface["name"] = "%s" % (host)
                else:
                    interface["name"] = "generic%d" % counter

                # add references to the system, profile, and distro
                # for use in the template
                if system.name in blender_cache:
                    blended_system = blender_cache[system.name]
                else:
                    blended_system = utils.blender(self.api, False, system)
                    blender_cache[system.name] = blended_system

                interface["next_server"] = blended_system["next_server"]
                interface["filename"] = blended_system.get("filename")
                interface["netboot_enabled"] = blended_system["netboot_enabled"]
                interface["hostname"] = blended_system["hostname"]
                interface["owner"] = blended_system["name"]
                interface["enable_gpxe"] = blended_system["enable_gpxe"]
                interface["name_servers"] = blended_system["name_servers"]
                interface["mgmt_parameters"] = blended_system["mgmt_parameters"]

                # Explicitly declare filename for other (non x86) archs as in DHCP discover package mostly the
                # architecture cannot be differed due to missing bits...
                if distro is not None and not interface.get("filename"):
                    if distro.arch == "ppc" or distro.arch == "ppc64":
                        interface["filename"] = yaboot
                    elif distro.arch == "ppc64le":
                        interface["filename"] = "grub/grub.ppc64le"
                    elif distro.arch == "aarch64":
                        interface["filename"] = "grub/grubaa64.efi"

                if not self.settings.always_write_dhcp_entries:
                    if not interface["netboot_enabled"] and interface['static']:
                        continue

                if dhcp_tag == "":
                    dhcp_tag = blended_system.get("dhcp_tag", "")
                    if dhcp_tag == "":
                        dhcp_tag = "default"

                if dhcp_tag not in dhcp_tags:
                    dhcp_tags[dhcp_tag] = {
                        mac: interface
                    }
                else:
                    dhcp_tags[dhcp_tag][mac] = interface

        # Remove macs from redundant slave interfaces from dhcp_tags otherwise you get duplicate ip's in the installer.
        for dt in list(dhcp_tags.keys()):
            for m in list(dhcp_tags[dt].keys()):
                if m in ignore_macs:
                    del dhcp_tags[dt][m]

        # we are now done with the looping through each interface of each system
        metadata = {
            "date": time.asctime(time.gmtime()),
            "cobbler_server": "%s:%s" % (self.settings.server, self.settings.http_port),
            "next_server": self.settings.next_server,
            "yaboot": yaboot,
            "dhcp_tags": dhcp_tags
        }

        self.logger.info("generating %s", self.settings_file)
        self.templar.render(template_data, metadata, self.settings_file)
예제 #36
0
def run(api, args):
    settings = api.settings()
    if not settings.windows_enabled:
        return 0
    if not HAS_HIVEX:
        logger.info(
            "python3-hivex or python3-pefile not found. If you need Automatic Windows Installation support, "
            "please install.")
        return 0

    profiles = api.profiles()
    systems = api.systems()
    templ = templar.Templar(api._collection_mgr)
    tgen = tftpgen.TFTPGen(api._collection_mgr)

    with open(
            os.path.join(settings.windows_template_dir,
                         post_inst_cmd_template_name)) as template_win:
        post_tmpl_data = template_win.read()

    with open(
            os.path.join(settings.windows_template_dir,
                         answerfile_template_name)) as template_win:
        tmpl_data = template_win.read()

    with open(
            os.path.join(settings.windows_template_dir,
                         startnet_template_name)) as template_start:
        tmplstart_data = template_start.read()

    def gen_win_files(distro, meta):
        (kernel_path, kernel_name) = os.path.split(distro.kernel)
        distro_path = utils.find_distro_path(settings, distro)
        distro_dir = wim_file_name = os.path.join(settings.tftpboot_location,
                                                  "images", distro.name)
        web_dir = os.path.join(settings.webdir, "images", distro.name)
        is_winpe = "winpe" in meta and meta['winpe'] != ""
        is_bcd = "bcd" in meta and meta['bcd'] != ""

        if "kernel" in meta:
            kernel_name = meta["kernel"]

        kernel_name = os.path.basename(kernel_name)
        is_wimboot = "wimboot" in kernel_name

        if is_wimboot:
            distro_path = os.path.join(settings.webdir, "distro_mirror",
                                       distro.name)
            kernel_path = os.path.join(distro_path, "Boot")

            if "kernel" in meta and "wimboot" not in distro.kernel:
                tgen.copy_single_distro_file(
                    os.path.join(settings.tftpboot_location, kernel_name),
                    distro_dir, False)
                tgen.copy_single_distro_file(
                    os.path.join(distro_dir, kernel_name), web_dir, True)

        if "post_install_script" in meta:
            post_install_dir = distro_path

            if distro.os_version not in ("XP", "2003"):
                post_install_dir = os.path.join(post_install_dir, "sources")

            post_install_dir = os.path.join(post_install_dir, "$OEM$", "$1")

            if not os.path.exists(post_install_dir):
                utils.mkdir(post_install_dir)

            data = templ.render(post_tmpl_data, meta, None)
            post_install_script = os.path.join(post_install_dir,
                                               meta["post_install_script"])
            logger.info('Build post install script: ' + post_install_script)
            with open(post_install_script, "w+") as pi_file:
                pi_file.write(data)

        if "answerfile" in meta:
            data = templ.render(tmpl_data, meta, None)
            answerfile_name = os.path.join(distro_dir, meta["answerfile"])
            logger.info('Build answer file: ' + answerfile_name)
            with open(answerfile_name, "w+") as answerfile:
                answerfile.write(data)
            tgen.copy_single_distro_file(answerfile_name, distro_path, False)
            tgen.copy_single_distro_file(answerfile_name, web_dir, True)

        if "kernel" in meta and "bootmgr" in meta:
            wk_file_name = os.path.join(distro_dir, kernel_name)
            wl_file_name = os.path.join(distro_dir, meta["bootmgr"])
            tl_file_name = os.path.join(kernel_path, "bootmgr.exe")

            if distro.os_version in ("XP", "2003") and not is_winpe:
                tl_file_name = os.path.join(kernel_path, "setupldr.exe")

                if len(meta["bootmgr"]) != 5:
                    logger.error(
                        "The loader name should be EXACTLY 5 character")
                    return 1

                pat1 = re.compile(br'NTLDR', re.IGNORECASE)
                pat2 = re.compile(br'winnt\.sif', re.IGNORECASE)
                with open(tl_file_name, 'rb') as file:
                    out = data = file.read()

                if "answerfile" in meta:
                    if len(meta["answerfile"]) != 9:
                        logger.error(
                            "The response file name should be EXACTLY 9 character"
                        )
                        return 1

                    out = pat2.sub(bytes(meta["answerfile"], 'utf-8'), data)
            else:
                if len(meta["bootmgr"]) != 11:
                    logger.error(
                        "The Boot manager file name should be EXACTLY 11 character"
                    )
                    return 1

                bcd_name = "bcd"
                if is_bcd:
                    bcd_name = meta["bcd"]
                    if len(bcd_name) != 3:
                        logger.error(
                            "The BCD file name should be EXACTLY 3 character")
                        return 1

                if not os.path.isfile(tl_file_name):
                    logger.error("File not found: %s" % tl_file_name)
                    return 1

                pat1 = re.compile(br'bootmgr\.exe', re.IGNORECASE)
                pat2 = re.compile(br'(\\.B.o.o.t.\\.)(B)(.)(C)(.)(D)',
                                  re.IGNORECASE)

                bcd_name = bytes(
                    "\\g<1>" + bcd_name[0] + "\\g<3>" + bcd_name[1] +
                    "\\g<5>" + bcd_name[2], 'utf-8')
                with open(tl_file_name, 'rb') as file:
                    out = file.read()

                if not is_wimboot:
                    logger.info('Patching build Loader: %s' % wl_file_name)
                    out = pat2.sub(bcd_name, out)

            if tl_file_name != wl_file_name:
                logger.info('Build Loader: %s from %s' %
                            (wl_file_name, tl_file_name))
                with open(wl_file_name, 'wb+') as file:
                    file.write(out)
                tgen.copy_single_distro_file(wl_file_name, web_dir, True)

            if not is_wimboot:
                if distro.os_version not in ("XP", "2003") or is_winpe:
                    pe = pefile.PE(wl_file_name, fast_load=True)
                    pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum()
                    pe.write(filename=wl_file_name)

                with open(distro.kernel, 'rb') as file:
                    data = file.read()
                out = pat1.sub(bytes(meta["bootmgr"], 'utf-8'), data)

                if wk_file_name != distro.kernel:
                    logger.info("Build PXEBoot: %s from %s" %
                                (wk_file_name, distro.kernel))
                    with open(wk_file_name, 'wb+') as file:
                        file.write(out)
                    tgen.copy_single_distro_file(wk_file_name, web_dir, True)

        if is_bcd:
            obcd_file_name = os.path.join(kernel_path, "bcd")
            bcd_file_name = os.path.join(distro_dir, meta["bcd"])
            wim_file_name = 'winpe.wim'

            if not os.path.isfile(obcd_file_name):
                logger.error("File not found: %s" % obcd_file_name)
                return 1

            if is_winpe:
                wim_file_name = meta["winpe"]

            if is_wimboot:
                wim_file_name = '\\Boot\\' + wim_file_name
                sdi_file_name = '\\Boot\\' + 'boot.sdi'
            else:
                wim_file_name = os.path.join("/images", distro.name,
                                             wim_file_name)
                sdi_file_name = os.path.join("/images", distro.name,
                                             os.path.basename(distro.initrd))

            logger.info('Build BCD: %s from %s for %s' %
                        (bcd_file_name, obcd_file_name, wim_file_name))
            bcdedit(obcd_file_name, bcd_file_name, wim_file_name,
                    sdi_file_name)
            tgen.copy_single_distro_file(bcd_file_name, web_dir, True)

        if is_winpe:
            ps_file_name = os.path.join(distro_dir, meta["winpe"])
            wim_pl_name = os.path.join(kernel_path, "winpe.wim")

            cmd = ["/usr/bin/cp", "--reflink=auto", wim_pl_name, ps_file_name]
            utils.subprocess_call(logger, cmd, shell=False)
            tgen.copy_single_distro_file(ps_file_name, web_dir, True)

            if os.path.exists(wimupdate):
                data = templ.render(tmplstart_data, meta, None)
                pi_file = tempfile.NamedTemporaryFile()
                pi_file.write(bytes(data, 'utf-8'))
                pi_file.flush()
                cmd = [
                    wimupdate, ps_file_name, "--command=add " + pi_file.name +
                    " /Windows/System32/startnet.cmd"
                ]
                utils.subprocess_call(cmd, shell=False)
                pi_file.close()

    for profile in profiles:
        distro = profile.get_conceptual_parent()

        if distro and distro.breed == "windows":
            logger.info('Profile: ' + profile.name)
            meta = utils.blender(api, False, profile)
            autoinstall_meta = meta.get("autoinstall_meta", {})
            meta.update(autoinstall_meta)
            gen_win_files(distro, meta)

    for system in systems:
        profile = system.get_conceptual_parent()
        autoinstall_meta = system.autoinstall_meta

        if not profile or not autoinstall_meta or autoinstall_meta == {}:
            continue

        distro = profile.get_conceptual_parent()

        if distro and distro.breed == "windows":
            logger.info('System: ' + system.name)
            meta = utils.blender(api, False, system)
            gen_win_files(distro, autoinstall_meta)
    return 0
예제 #37
0
def run(api, args):
    if not HAS_HIVEX:
        logger.info("python3-hivex or python3-pefile not found. If you need Automatic Windows Installation support, "
                    "please install.")
        return 0

    distros = api.distros()
    profiles = api.profiles()
    templ = templar.Templar(api._collection_mgr)
    template_win = open(post_inst_cmd_template_name)
    tmpl_data = template_win.read()
    template_win.close()

    for distro in distros:
        if distro.breed == "windows":
            meta = utils.blender(api, False, distro)

            if "post_install" in distro.kernel_options:
                data = templ.render(tmpl_data, meta, None)
                pi_file = open(distro.kernel_options["post_install"], "w+")
                pi_file.write(data)
                pi_file.close()

    template_win = open(sif_template_name)
    tmpl_data = template_win.read()
    template_win.close()

    template_start = open(startnet_template_name)
    tmplstart_data = template_start.read()
    template_start.close()

    logger.info("\nWindows profiles:")

    for profile in profiles:
        distro = profile.get_conceptual_parent()

        if distro.breed == "windows":
            logger.info('Profile: ' + profile.name)
            meta = utils.blender(api, False, profile)
            (distro_path, pxeboot_name) = os.path.split(distro.kernel)

            if "sif" in profile.kernel_options:
                data = templ.render(tmpl_data, meta, None)

                if distro.os_version in ("7", "2008", "8", "2012", "2016", "2019", "10"):
                    sif_file_name = os.path.join(distro_path, 'sources', profile.kernel_options["sif"])
                else:
                    sif_file_name = os.path.join(distro_path, profile.kernel_options["sif"])

                sif_file = open(sif_file_name, "w+")
                sif_file.write(data)
                sif_file.close()
                logger.info('Build answer file: ' + sif_file_name)

            if "pxeboot" in profile.kernel_options and "bootmgr" in profile.kernel_options:
                wk_file_name = os.path.join(distro_path, profile.kernel_options["pxeboot"])
                wl_file_name = os.path.join(distro_path, profile.kernel_options["bootmgr"])
                logger.info("Build PXEBoot: " + wk_file_name)

                if distro.os_version in ("7", "2008", "8", "2012", "2016", "2019", "10"):
                    if len(profile.kernel_options["bootmgr"]) != 11:
                        logger.error("The loader  name should be EXACTLY 11 character")
                        return 1

                    if "bcd" in profile.kernel_options:
                        if len(profile.kernel_options["bcd"]) != 3:
                            logger.error("The BCD name should be EXACTLY 5 character")
                            return 1

                    tl_file_name = os.path.join(distro_path, 'bootmgr.exe')
                    pat1 = re.compile(br'bootmgr\.exe', re.IGNORECASE)
                    pat2 = re.compile(br'(\\.B.o.o.t.\\.)(B)(.)(C)(.)(D)', re.IGNORECASE)
                    bcd_name = 'BCD'

                    if "bcd" in profile.kernel_options:
                        bcd_name = profile.kernel_options["bcd"]

                    bcd_name = bytes("\\g<1>" + bcd_name[0] + "\\g<3>" + bcd_name[1] + "\\g<5>" + bcd_name[2], 'utf-8')
                    data = open(tl_file_name, 'rb').read()
                    out = pat2.sub(bcd_name, data)
                else:
                    if len(profile.kernel_options["bootmgr"]) != 5:
                        logger.error("The loader name should be EXACTLY 5 character")
                        return 1

                    if len(profile.kernel_options["sif"]) != 9:
                        logger.error("The response should be EXACTLY 9 character")
                        return 1

                    tl_file_name = os.path.join(distro_path, 'setupldr.exe')
                    pat1 = re.compile(br'NTLDR', re.IGNORECASE)
                    pat2 = re.compile(br'winnt\.sif', re.IGNORECASE)

                    data = open(tl_file_name, 'rb').read()
                    out = pat2.sub(bytes(profile.kernel_options["sif"], 'utf-8'), data)

                logger.info('Build Loader: ' + wl_file_name)

                if out != data:
                    open(wl_file_name, 'wb+').write(out)

                if distro.os_version in ("7", "2008", "8", "2012", "2016", "2019", "10"):
                    pe = pefile.PE(wl_file_name, fast_load=True)
                    pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum()
                    pe.write(filename=wl_file_name)

                data = open(distro.kernel, 'rb').read()
                out = pat1.sub(bytes(profile.kernel_options["bootmgr"], 'utf-8'), data)

                if out != data:
                    open(wk_file_name, 'wb+').write(out)

            if "bcd" in profile.kernel_options:
                obcd_file_name = os.path.join(distro_path, 'boot', 'BCD')
                bcd_file_name = os.path.join(distro_path, 'boot', profile.kernel_options["bcd"])
                wim_file_name = 'winpe.wim'

                if "winpe" in profile.kernel_options:
                    wim_file_name = profile.kernel_options["winpe"]

                if distro.boot_loader == "ipxe":
                    wim_file_name = '\\Boot\\' + wim_file_name
                    sdi_file_name = '\\Boot\\' + 'boot.sdi'
                else:
                    wim_file_name = os.path.join('/winos', distro.name, 'boot', wim_file_name)
                    sdi_file_name = os.path.join('/winos', distro.name, 'boot', 'boot.sdi')

                logger.info('Build BCD: ' + bcd_file_name + ' for ' + wim_file_name)
                bcdedit(obcd_file_name, bcd_file_name, wim_file_name, sdi_file_name)

            if "winpe" in profile.kernel_options:
                ps_file_name = os.path.join(distro_path, "boot", profile.kernel_options["winpe"])

                if distro.os_version in ("7", "2008"):
                    wim_pl_name = wim7_template_name
                elif distro.os_version in ("8", "2012", "2016", "2019", "10"):
                    wim_pl_name = wim8_template_name
                else:
                    raise ValueError("You are trying to use an unsupported distro!")

                cmd = "/usr/bin/cp --reflink=auto " + wim_pl_name + " " + ps_file_name
                utils.subprocess_call(cmd, shell=True)

                if os.path.exists(wimupdate):
                    data = templ.render(tmplstart_data, meta, None)
                    pi_file = tempfile.NamedTemporaryFile()
                    pi_file.write(bytes(data, 'utf-8'))
                    pi_file.flush()
                    cmd = wimupdate + ' ' + ps_file_name + ' --command="add ' + pi_file.name
                    cmd += ' /Windows/System32/startnet.cmd"'
                    utils.subprocess_call(cmd, shell=True)
                    pi_file.close()
    return 0
예제 #38
0
    def generate_autoyast(self, profile=None, system=None, raw_data=None):
        self.api.logger.info("autoyast XML file found. Checkpoint: profile=%s system=%s" % (profile, system))
        nopxe = "\nwget \"http://%s/cblr/svc/op/nopxe/system/%s\" -O /dev/null"
        runpost = "\ncurl \"http://%s/cblr/svc/op/trig/mode/post/%s/%s\" > /dev/null"
        runpre = "\nwget \"http://%s/cblr/svc/op/trig/mode/pre/%s/%s\" -O /dev/null"

        what = "profile"
        blend_this = profile
        if system:
            what = "system"
            blend_this = system
        blended = utils.blender(self.api, False, blend_this)
        srv = blended["http_server"]

        document = xml.dom.minidom.parseString(raw_data)

        # do we already have the #raw comment in the XML? (addComment = 0 means, don't add #raw comment)
        addComment = 1
        for node in document.childNodes[1].childNodes:
            if node.nodeType == node.ELEMENT_NODE and node.tagName == "cobbler":
                addComment = 0
                break

        # add some cobbler information to the XML file
        # maybe that should be configureable
        if addComment == 1:
            # startComment = document.createComment("\ncobbler_system_name=$system_name\ncobbler_server=$server\n#raw\n")
            # endComment = document.createComment("\n#end raw\n")
            cobblerElement = document.createElement("cobbler")
            cobblerElementSystem = xml.dom.minidom.Element("system_name")
            cobblerElementProfile = xml.dom.minidom.Element("profile_name")
            if (system is not None):
                cobblerTextSystem = document.createTextNode(system.name)
                cobblerElementSystem.appendChild(cobblerTextSystem)
            if (profile is not None):
                cobblerTextProfile = document.createTextNode(profile.name)
                cobblerElementProfile.appendChild(cobblerTextProfile)

            cobblerElementServer = document.createElement("server")
            cobblerTextServer = document.createTextNode(blended["http_server"])
            cobblerElementServer.appendChild(cobblerTextServer)

            cobblerElement.appendChild(cobblerElementServer)
            cobblerElement.appendChild(cobblerElementSystem)
            cobblerElement.appendChild(cobblerElementProfile)

            # FIXME: this is all broken and no longer works.
            #        this entire if block should probably not be
            #        hard-coded anyway
            # self.api.log(document.childNodes[2].childNodes)
            # document.childNodes[1].insertBefore( cobblerElement, document.childNodes[2].childNodes[1])
            # document.childNodes[1].insertBefore( cobblerElement, document.childNodes[1].childNodes[0])

        name = profile.name
        if system is not None:
            name = system.name

        if str(self.settings.pxe_just_once).upper() in ["1", "Y", "YES", "TRUE"]:
            self.addAutoYaSTScript(document, "chroot-scripts", nopxe % (srv, name))
        if self.settings.run_install_triggers:
            # notify cobblerd when we start/finished the installation
            self.addAutoYaSTScript(document, "pre-scripts", runpre % (srv, what, name))
            self.addAutoYaSTScript(document, "init-scripts", runpost % (srv, what, name))

        return document.toxml()
예제 #39
0
파일: item.py 프로젝트: whitekid/cobbler
 def dump_vars(self, data, format=True):
     raw = utils.blender(self.config.api, False, self)
     if format:
         return pprint.pformat(raw)
     else:
         return raw
예제 #40
0
 def dump_vars(self, data, format=True):
     raw = utils.blender(self.collection_mgr.api, False, self)
     if format:
         return pprint.pformat(raw)
     else:
         return raw
예제 #41
0
    def generate_repo_stanza(self, obj, is_profile=True):
        """
        Automatically attaches yum repos to profiles/systems in automatic installation files (template files) that
        contain the magic $yum_repo_stanza variable. This includes repo objects as well as the yum repos that are part
        of split tree installs, whose data is stored with the distro (example: RHEL5 imports)

        :param obj: The profile or system to generate the repo stanza for.
        :param is_profile: If True then obj is a profile, otherwise obj has to be a system. Otherwise this method will
                           silently fail.
        :return: The string with the attached yum repos.
        :rtype: str
        """

        buf = ""
        blended = utils.blender(self.api, False, obj)
        repos = blended["repos"]

        # keep track of URLs and be sure to not include any duplicates
        included = {}

        for repo in repos:
            # see if this is a source_repo or not
            repo_obj = self.api.find_repo(repo)
            if repo_obj is not None:
                yumopts = ''
                for opt in repo_obj.yumopts:
                    # filter invalid values to the repo statement in automatic installation files

                    if opt in ['exclude', 'include']:
                        value = repo_obj.yumopts[opt].replace(' ', ',')
                        yumopts = yumopts + " --%spkgs=%s" % (opt, value)
                    elif not opt.lower(
                    ) in validate.AUTOINSTALL_REPO_BLACKLIST:
                        yumopts += " %s=%s" % (opt, repo_obj.yumopts[opt])
                if 'enabled' not in repo_obj.yumopts or repo_obj.yumopts[
                        'enabled'] == '1':
                    if repo_obj.mirror_locally:
                        baseurl = "http://%s/cobbler/repo_mirror/%s" % (
                            blended["http_server"], repo_obj.name)
                        if baseurl not in included:
                            buf += "repo --name=%s --baseurl=%s\n" % (
                                repo_obj.name, baseurl)
                        included[baseurl] = 1
                    else:
                        if repo_obj.mirror not in included:
                            buf += "repo --name=%s --baseurl=%s %s\n" % (
                                repo_obj.name, repo_obj.mirror, yumopts)
                        included[repo_obj.mirror] = 1
            else:
                # FIXME: what to do if we can't find the repo object that is listed?
                # This should be a warning at another point, probably not here so we'll just not list it so the
                # automatic installation file will still work as nothing will be here to read the output noise.
                # Logging might be useful.
                pass

        if is_profile:
            distro = obj.get_conceptual_parent()
        else:
            distro = obj.get_conceptual_parent().get_conceptual_parent()

        source_repos = distro.source_repos
        count = 0
        for x in source_repos:
            count += 1
            if not x[1] in included:
                buf += "repo --name=source-%s --baseurl=%s\n" % (count, x[1])
                included[x[1]] = 1

        return buf
예제 #42
0
def run(api, args, logger):
    # FIXME: make everything use the logger

    settings = api.settings()

    # go no further if this feature is turned off
    if not str(settings.build_reporting_enabled).lower() in ["1", "yes", "y", "true"]:
        return 0

    objtype = args[0]   # "target" or "profile"
    name = args[1]      # name of target or profile
    boot_ip = args[2]   # ip or "?"

    if objtype == "system":
        target = api.find_system(name)
    else:
        target = api.find_profile(name)

    # collapse the object down to a rendered datastructure
    target = utils.blender(api, False, target)

    if target == {}:
        raise CX("failure looking up target")

    to_addr = settings.build_reporting_email
    if to_addr == "":
        return 0

    # add the ability to specify an MTA for servers that don't run their own
    smtp_server = settings.build_reporting_smtp_server
    if smtp_server == "":
        smtp_server = "localhost"

    # use a custom from address or fall back to a reasonable default
    from_addr = settings.build_reporting_sender
    if from_addr == "":
        from_addr = "cobbler@%s" % settings.server

    subject = settings.build_reporting_subject
    if subject == "":
        subject = '[Cobbler] install complete '

    to_addr = ",".join(to_addr)
    metadata = {
        "from_addr": from_addr,
        "to_addr": to_addr,
        "subject": subject,
        "boot_ip": boot_ip
    }
    metadata.update(target)

    input_template = open("/etc/cobbler/reporting/build_report_email.template")
    input_data = input_template.read()
    input_template.close()

    message = templar.Templar(api._config).render(input_data, metadata, None)

    sendmail = True
    for prefix in settings.build_reporting_ignorelist:
        if prefix != '' and name.lower().startswith(prefix):
            sendmail = False

    if sendmail:
        # Send the mail
        # FIXME: on error, return non-zero
        server_handle = smtplib.SMTP(smtp_server)
        server_handle.sendmail(from_addr, to_addr.split(','), message)
        server_handle.quit()

    return 0
예제 #43
0
    def write_dhcp_file(self):
        """
        DHCP files are written when manage_dhcp is set in
        /etc/cobbler/settings.
        """

        template_file = "/etc/cobbler/dhcp.template"
        blender_cache = {}

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error reading template: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        # use a simple counter for generating generic names where a hostname
        # is not available
        counter = 0

        # we used to just loop through each system, but now we must loop
        # through each network interface of each system.
        dhcp_tags = {"default": {}}
        yaboot = "/yaboot"

        # FIXME: ding should evolve into the new dhcp_tags dict
        ding = {}
        ignore_macs = []

        for system in self.systems:
            if not system.is_management_supported(cidr_ok=False):
                continue

            profile = system.get_conceptual_parent()
            distro = profile.get_conceptual_parent()

            # if distro is None then the profile is really an image record
            for (name, system_interface) in list(system.interfaces.items()):

                # We make a copy because we may modify it before adding it to the dhcp_tags
                # and we don't want to affect the master copy.
                interface = copy.deepcopy(system_interface)

                if interface["if_gateway"]:
                    interface["gateway"] = interface["if_gateway"]
                else:
                    interface["gateway"] = system.gateway

                mac = interface["mac_address"]

                if interface["interface_type"] in ("bond_slave", "bridge_slave", "bonded_bridge_slave"):

                    if interface["interface_master"] not in system.interfaces:
                        # Can't write DHCP entry; master interface does not exist
                        continue

                    # We may have multiple bonded interfaces, so we need a composite index into ding.
                    name_master = "%s-%s" % (system.name, interface["interface_master"])
                    if name_master not in ding:
                        ding[name_master] = {interface["interface_master"]: []}

                    if len(ding[name_master][interface["interface_master"]]) == 0:
                        ding[name_master][interface["interface_master"]].append(mac)
                    else:
                        ignore_macs.append(mac)

                    ip = system.interfaces[interface["interface_master"]]["ip_address"]
                    netmask = system.interfaces[interface["interface_master"]]["netmask"]
                    dhcp_tag = system.interfaces[interface["interface_master"]]["dhcp_tag"]
                    host = system.interfaces[interface["interface_master"]]["dns_name"]

                    if ip is None or ip == "":
                        for (nam2, int2) in list(system.interfaces.items()):
                            if (nam2.startswith(interface["interface_master"] + ".") and int2["ip_address"] is not None and int2["ip_address"] != ""):
                                ip = int2["ip_address"]
                                break

                    interface["ip_address"] = ip
                    interface["netmask"] = netmask
                else:
                    ip = interface["ip_address"]
                    netmask = interface["netmask"]
                    dhcp_tag = interface["dhcp_tag"]
                    host = interface["dns_name"]

                if distro is not None:
                    interface["distro"] = distro.to_dict()

                if mac is None or mac == "":
                    # can't write a DHCP entry for this system
                    continue

                counter = counter + 1

                # the label the entry after the hostname if possible
                if host is not None and host != "":
                    if name != "eth0":
                        interface["name"] = "%s-%s" % (host, name)
                    else:
                        interface["name"] = "%s" % (host)
                else:
                    interface["name"] = "generic%d" % counter

                # add references to the system, profile, and distro
                # for use in the template
                if system.name in blender_cache:
                    blended_system = blender_cache[system.name]
                else:
                    blended_system = utils.blender(self.api, False, system)
                    blender_cache[system.name] = blended_system

                interface["next_server"] = blended_system["next_server"]
                interface["netboot_enabled"] = blended_system["netboot_enabled"]
                interface["hostname"] = blended_system["hostname"]
                interface["owner"] = blended_system["name"]
                interface["enable_gpxe"] = blended_system["enable_gpxe"]
                interface["name_servers"] = blended_system["name_servers"]

                if not self.settings.always_write_dhcp_entries:
                    if not interface["netboot_enabled"] and interface['static']:
                        continue

                if distro is not None:
                    if distro.arch.startswith("ppc"):
                        if blended_system["boot_loader"] == "pxelinux":
                            del interface["filename"]
                        elif distro.boot_loader == "grub2" or blended_system["boot_loader"] == "grub2":
                            interface["filename"] = "boot/grub/powerpc-ieee1275/core.elf"
                        else:
                            interface["filename"] = yaboot

                if dhcp_tag == "":
                    dhcp_tag = blended_system["dhcp_tag"]
                    if dhcp_tag == "":
                        dhcp_tag = "default"

                if dhcp_tag not in dhcp_tags:
                    dhcp_tags[dhcp_tag] = {
                        mac: interface
                    }
                else:
                    dhcp_tags[dhcp_tag][mac] = interface

        # remove macs from redundant slave interfaces from dhcp_tags
        # otherwise you get duplicate ip's in the installer
        for dt in list(dhcp_tags.keys()):
            for m in list(dhcp_tags[dt].keys()):
                if m in ignore_macs:
                    del dhcp_tags[dt][m]

        # we are now done with the looping through each interface of each system
        metadata = {
            "date": time.asctime(time.gmtime()),
            "cobbler_server": "%s:%s" % (self.settings.server, self.settings.http_port),
            "next_server": self.settings.next_server,
            "yaboot": yaboot,
            "dhcp_tags": dhcp_tags
        }

        if self.logger is not None:
            self.logger.info("generating %s" % self.settings_file)
        self.templar.render(template_data, metadata, self.settings_file, None)