Exemple #1
0
    def _crushmap_root_delete(self, name):
        """Remove the crushmap root entry. """

        default_root_name = self._format_root_name(self._default_tier)
        root_name = self._format_root_name(name)
        if root_name == default_root_name:
            reason = "Cannot remove tier '%s'." % default_root_name
            raise exception.CephCrushInvalidTierUse(tier=name, reason=reason)

        response, body = self._ceph_api.osd_crush_tree(body='json')
        if response.status_code == requests.codes.ok:
            # Scan for the destinaion root, should not be present
            root = [r for r in body['output'] if r['name'] == root_name]

            if not root:
                reason = "The crushmap root '%s' does not exist." % root_name
                raise exception.CephCrushInvalidTierUse(tier=name,
                                                        reason=reason)

            # Delete the root hierarchy
            try:
                self._crushmap_item_delete(root, name)
            except exception.CephCrushMaxRecursion:
                LOG.debug("Unexpected recursion level seen while deleting "
                          "crushmap hierarchy")
Exemple #2
0
    def _crushmap_root_mirror(self, src_name, dest_name):
        """Create a new root hierarchy that matches an existing root hierarchy.
        """

        # Nomenclature for mirrored tiers:
        # root XXX-tier
        #     chassis group-0-XXX
        #         host storage-0-XXX
        #         host storage-1-XXX
        src_root_name = self._format_root_name(src_name)
        dest_root_name = self._format_root_name(dest_name)

        # currently prevent mirroring of anything other than the source tier
        default_root_name = self._format_root_name(self._default_tier)
        if src_root_name != default_root_name:
            reason = "Can only mirror '%s'." % default_root_name
            raise exception.CephCrushInvalidTierUse(tier=src_name,
                                                    reason=reason)

        response, body = self._ceph_api.osd_crush_tree(body='json')
        if response.status_code == requests.codes.ok:
            # Scan for the destination root, should not be present
            dest_root = [
                r for r in body['output'] if r['name'] == dest_root_name
            ]
            if dest_root:
                reason = "Tier '%s' already exists." % dest_root_name
                raise exception.CephCrushInvalidTierUse(tier=dest_root_name,
                                                        reason=reason)

            src_root = [
                r for r in body['output'] if r['name'] == src_root_name
            ]
            if not src_root:
                reason = ("The required source root '%s' does not exist." %
                          src_root_name)
                raise exception.CephCrushInvalidTierUse(tier=src_root_name,
                                                        reason=reason)

            # Mirror the root hierarchy
            LOG.info("Mirroring crush root for new tier: src = %s, dest = %s" %
                     (src_root_name, dest_root_name))
            try:
                self._crushmap_item_create(src_root, dest_name)
            except exception.CephCrushMaxRecursion:
                LOG.error("Unexpected recursion level seen while mirroring "
                          "crushmap hierarchy. Rolling back crushmap changes")
                self._crushmap_item_delete(src_root, dest_name, rollback=True)
Exemple #3
0
    def _crushmap_rule_delete(self, name):
        """Delete existing tier crushmap rule. """

        crushmap_flag_file = os.path.join(constants.SYSINV_CONFIG_PATH,
                                          constants.CEPH_CRUSH_MAP_APPLIED)
        if not os.path.isfile(crushmap_flag_file):
            reason = "Cannot remove any additional rules."
            raise exception.CephCrushMapNotApplied(reason=reason)

        default_root_name = self._format_root_name(self._default_tier)
        root_name = self._format_root_name(name)
        if root_name == default_root_name:
            reason = (("Cannot remove the rule for tier '%s'.") %
                      default_root_name)
            raise exception.CephCrushInvalidTierUse(tier=name, reason=reason)

        # get the current rule count
        rule_is_present, rule_name, rule_count = self._crush_rule_status(
            root_name)

        if not rule_is_present:
            reason = (("Rule '%s' is not present in the crushmap. No action "
                       "taken.") % rule_name)
            raise exception.CephCrushInvalidRuleOperation(rule=rule_name,
                                                          reason=reason)

        LOG.info("ceph osd crush rule rm %s" % rule_name)
        response, body = self._ceph_api.osd_crush_rule_rm(rule_name,
                                                          body='json')
        LOG.info("CRUSH: %d :%s" % (response.status_code, body['status']))
Exemple #4
0
    def _crushmap_rule_add(self, name, replicate_by):
        """Add a tier crushmap rule."""

        crushmap_flag_file = os.path.join(constants.SYSINV_CONFIG_PATH,
                                          constants.CEPH_CRUSH_MAP_APPLIED)
        if not os.path.isfile(crushmap_flag_file):
            reason = "Cannot add any additional rules."
            raise exception.CephCrushMapNotApplied(reason=reason)

        default_root_name = self._format_root_name(self._default_tier)
        root_name = self._format_root_name(name)
        if root_name == default_root_name:
            reason = (
                "Rule for the default storage tier '%s' already exists." %
                default_root_name)
            raise exception.CephCrushInvalidTierUse(tier=name, reason=reason)

        # get the current rule count
        rule_is_present, rule_name, rule_count = self._crush_rule_status(
            root_name)

        if rule_is_present:
            reason = (
                ("Rule '%s' is already present in the crushmap. No action "
                 "taken.") % rule_name)
            raise exception.CephCrushInvalidRuleOperation(rule=rule_name,
                                                          reason=reason)

        # NOTE: The Ceph API only supports simple single step rule creation.
        # Because of this we need to update the crushmap the hard way.

        tmp_crushmap_bin_file = os.path.join(constants.SYSINV_CONFIG_PATH,
                                             "crushmap_rule_update.bin")
        tmp_crushmap_txt_file = os.path.join(constants.SYSINV_CONFIG_PATH,
                                             "crushmap_rule_update.txt")

        # Extract the crushmap
        cmd = ["ceph", "osd", "getcrushmap", "-o", tmp_crushmap_bin_file]
        stdout, __ = cutils.execute(*cmd, run_as_root=False)

        if os.path.exists(tmp_crushmap_bin_file):
            # Decompile the crushmap
            cmd = [
                "crushtool", "-d", tmp_crushmap_bin_file, "-o",
                tmp_crushmap_txt_file
            ]
            stdout, __ = cutils.execute(*cmd, run_as_root=False)

            if os.path.exists(tmp_crushmap_txt_file):
                # Add the custom rule
                with open(tmp_crushmap_txt_file, 'r') as fp:
                    contents = fp.readlines()

                self._insert_crush_rule(contents, root_name, rule_name,
                                        rule_count, replicate_by)

                with open(tmp_crushmap_txt_file, 'w') as fp:
                    contents = "".join(contents)
                    fp.write(contents)

                # Compile the crush map
                cmd = [
                    "crushtool", "-c", tmp_crushmap_txt_file, "-o",
                    tmp_crushmap_bin_file
                ]
                stdout, __ = cutils.execute(*cmd, run_as_root=False)

                # Load the new crushmap
                LOG.info("Loading updated crushmap with elements for "
                         "crushmap root: %s" % root_name)
                cmd = [
                    "ceph", "osd", "setcrushmap", "-i", tmp_crushmap_bin_file
                ]
                stdout, __ = cutils.execute(*cmd, run_as_root=False)

        # cleanup
        if os.path.exists(tmp_crushmap_txt_file):
            os.remove(tmp_crushmap_txt_file)
        if os.path.exists(tmp_crushmap_bin_file):
            os.remove(tmp_crushmap_bin_file)