Exemple #1
0
    def test_value_diff(self):

        current = {"cat": "meow", "dog": "woof", "horse": ["neigh", "whinny"]}

        new_values = {"dog": "bark", "horse": "snort"}

        original = copy.deepcopy(current)
        backup = utils.value_diff(current, new_values)

        self.assertEqual({"dog": "woof", "horse": ["neigh", "whinny"]}, backup)

        # current is unchanged
        self.assertEqual(original, current)
Exemple #2
0
    def test_value_diff(self):

        current = {"cat": "meow", "dog": "woof", "horse": ["neigh", "whinny"]}

        new_values = {"dog": "bark", "horse": "snort"}

        original = copy.deepcopy(current)
        backup = utils.value_diff(current, new_values)

        self.assertEqual({"dog": "woof", "horse": ["neigh", "whinny"]}, backup)

        # current is unchanged
        self.assertEqual(original, current)
Exemple #3
0
def add_cluster_templates(ctx, clusters, ng_dict):
    '''Add cluster templates to the database.

    The value of any node_group_template_id fields in cluster
    templates which reference a node group template in ng_dict by name
    will be changed to the id of the node group template.

    If there is an error in creating or updating a template, any templates
    that have already been created will be delete and any updates will
    be reversed.

    :param clusters: a list of dictionaries. Each dictionary
                     has a "template" entry holding the cluster template
                     and a "path" entry holding the path of the file
                     from which the template was read.
    :param ng_dict: a dictionary of node group template ids keyed
                    by node group template names
    '''

    error = False
    created = []
    updated = []

    def do_reversals(created, updated):
        reverse_cluster_template_updates(ctx, updated)
        reverse_cluster_template_creates(ctx, created)
        return True

    try:
        for cl in clusters:
            template = cl['template']

            # Fix up node_group_template_id fields
            u.substitute_ng_ids(template, ng_dict)

            # Name + tenant_id is unique, so search by name
            current = u.find_cluster_template_by_name(ctx, template['name'])
            if current:

                # Track what we see in the current template that is different
                # from our update values. Save it for possible rollback.
                # Note, this is not perfect because it does not recurse through
                # nested structures to get an exact diff, but it ensures that
                # we track only fields that are valid in the JSON schema
                updated_fields = u.value_diff(current.to_dict(), template)

                # Always attempt to update.  Since the template value is a
                # combination of JSON and config values, there is no useful
                # timestamp we can use to skip an update.
                # If sqlalchemy determines no change in fields, it will not
                # mark it as updated.

                # TODO(tmckay): why when I change the count in an
                # entry in node_groups does it not count as an update?
                # Probably a bug
                try:
                    template = conductor.API.cluster_template_update(
                        ctx, current['id'], template, ignore_default=True)
                except Exception as e:
                    LOG.warning(_LW("Update of cluster template {info} "
                                "failed, {reason}").format(
                                    info=u.name_and_id(current), reason=e))
                    raise Handled()

                if template['updated_at'] != current['updated_at']:
                    updated.append((template, updated_fields))
                    LOG.info(_LI("Updated cluster template {info} "
                             "from {path}").format(
                                 info=u.name_and_id(template),
                                 path=cl['path']))
                else:
                    LOG.debug("No change to cluster template {info} "
                              "from {path}".format(info=u.name_and_id(current),
                                                   path=cl["path"]))
            else:
                template["is_default"] = True
                try:
                    template = conductor.API.cluster_template_create(ctx,
                                                                     template)
                except Exception as e:
                    LOG.warning(_LW("Creation of cluster template "
                                "from {path} failed, {reason}").format(
                                    path=cl['path'],
                                    reason=e))
                    raise Handled()

                created.append(template)
                LOG.info(_LI("Created cluster template {info} "
                         "from {path}").format(info=u.name_and_id(template),
                                               path=cl['path']))

    except Handled:
        error = do_reversals(created, updated)

    except Exception as e:
        LOG.warning(_LW("Unhandled exception while processing "
                    "cluster templates, {reason}").format(reason=e))
        error = do_reversals(created, updated)

    return error
Exemple #4
0
def add_node_group_templates(ctx, node_groups):

    error = False
    ng_info = {"ids": {},
               "created": [],
               "updated": []}

    def do_reversals(ng_info):
        reverse_node_group_template_updates(ctx, ng_info["updated"])
        reverse_node_group_template_creates(ctx, ng_info["created"])
        return {}, True

    try:
        for ng in node_groups:
            template = ng['template']
            current = u.find_node_group_template_by_name(ctx, template['name'])
            if current:

                # Track what we see in the current template that is different
                # from our update values. Save it for possible rollback.
                # Note, this is not perfect because it does not recurse through
                # nested structures to get an exact diff, but it ensures that
                # we track only fields that are valid in the JSON schema
                updated_fields = u.value_diff(current.to_dict(), template)

                # Always attempt to update.  Since the template value is a
                # combination of JSON and config values, there is no useful
                # timestamp we can use to skip an update.
                # If sqlalchemy determines no change in fields, it will not
                # mark it as updated.
                try:
                    template = conductor.API.node_group_template_update(
                        ctx, current['id'], template, ignore_default=True)
                except Exception as e:
                    LOG.warning(_LW("Update of node group template {info} "
                                "failed, {reason}").format(
                                    info=u.name_and_id(current),
                                    reason=e))
                    raise Handled()

                if template['updated_at'] != current['updated_at']:
                    ng_info["updated"].append((template, updated_fields))
                    LOG.info(_LI("Updated node group template {info} "
                             "from {path}").format(
                                 info=u.name_and_id(template),
                                 path=ng["path"]))
                else:
                    LOG.debug("No change to node group template {info} "
                              "from {path}".format(
                                  info=u.name_and_id(current),
                                  path=ng['path']))
            else:
                template['is_default'] = True
                try:
                    template = conductor.API.node_group_template_create(
                        ctx, template)
                except Exception as e:
                    LOG.warning(_LW("Creation of node group template "
                                "from {path} failed, {reason}").format(
                                    path=ng['path'], reason=e))
                    raise Handled()

                ng_info["created"].append(template)
                LOG.info(_LI("Created node group template {info} "
                         "from {path}").format(info=u.name_and_id(template),
                                               path=ng["path"]))

            # For the purposes of substituion we need a dict of id by name
            ng_info["ids"][template['name']] = template['id']

    except Handled:
        ng_info, error = do_reversals(ng_info)

    except Exception as e:
        LOG.warning(_LW("Unhandled exception while processing "
                    "node group templates, {reason}").format(reason=e))
        ng_info, error = do_reversals(ng_info)

    return ng_info, error
Exemple #5
0
def add_cluster_templates(ctx, clusters, ng_dict):
    '''Add cluster templates to the database.

    The value of any node_group_template_id fields in cluster
    templates which reference a node group template in ng_dict by name
    will be changed to the id of the node group template.

    If there is an error in creating or updating a template, any templates
    that have already been created will be delete and any updates will
    be reversed.

    :param clusters: a list of dictionaries. Each dictionary
                     has a "template" entry holding the cluster template
                     and a "path" entry holding the path of the file
                     from which the template was read.
    :param ng_dict: a dictionary of node group template ids keyed
                    by node group template names
    '''

    error = False
    created = []
    updated = []

    def do_reversals(created, updated):
        reverse_cluster_template_updates(ctx, updated)
        reverse_cluster_template_creates(ctx, created)
        return True

    try:
        for cl in clusters:
            template = cl['template']

            # Fix up node_group_template_id fields
            u.substitute_ng_ids(template, ng_dict)

            # Name + tenant_id is unique, so search by name
            current = u.find_cluster_template_by_name(ctx, template['name'])
            if current:

                # Track what we see in the current template that is different
                # from our update values. Save it for possible rollback.
                # Note, this is not perfect because it does not recurse through
                # nested structures to get an exact diff, but it ensures that
                # we track only fields that are valid in the JSON schema
                updated_fields = u.value_diff(current.to_dict(), template)

                # Always attempt to update.  Since the template value is a
                # combination of JSON and config values, there is no useful
                # timestamp we can use to skip an update.
                # If sqlalchemy determines no change in fields, it will not
                # mark it as updated.

                # TODO(tmckay): why when I change the count in an
                # entry in node_groups does it not count as an update?
                # Probably a bug
                try:
                    template = conductor.API.cluster_template_update(
                        ctx, current['id'], template, ignore_prot_on_def=True)
                except Exception as e:
                    LOG.warning(
                        _LW("Update of cluster template {info} "
                            "failed, {reason}").format(
                                info=u.name_and_id(current), reason=e))
                    raise Handled()

                if template['updated_at'] != current['updated_at']:
                    updated.append((template, updated_fields))
                    LOG.info(
                        _LI("Updated cluster template {info} "
                            "from {path}").format(info=u.name_and_id(template),
                                                  path=cl['path']))
                else:
                    LOG.debug("No change to cluster template {info} "
                              "from {path}".format(info=u.name_and_id(current),
                                                   path=cl["path"]))
            else:
                template["is_default"] = True
                try:
                    template = conductor.API.cluster_template_create(
                        ctx, template)
                except Exception as e:
                    LOG.warning(
                        _LW("Creation of cluster template "
                            "from {path} failed, {reason}").format(
                                path=cl['path'], reason=e))
                    raise Handled()

                created.append(template)
                LOG.info(
                    _LI("Created cluster template {info} "
                        "from {path}").format(info=u.name_and_id(template),
                                              path=cl['path']))

    except Handled:
        error = do_reversals(created, updated)

    except Exception as e:
        LOG.warning(
            _LW("Unhandled exception while processing "
                "cluster templates, {reason}").format(reason=e))
        error = do_reversals(created, updated)

    return error
Exemple #6
0
def add_node_group_templates(ctx, node_groups):

    error = False
    ng_info = {"ids": {}, "created": [], "updated": []}

    def do_reversals(ng_info):
        reverse_node_group_template_updates(ctx, ng_info["updated"])
        reverse_node_group_template_creates(ctx, ng_info["created"])
        return {}, True

    try:
        for ng in node_groups:
            template = ng['template']
            current = u.find_node_group_template_by_name(ctx, template['name'])
            if current:

                # Track what we see in the current template that is different
                # from our update values. Save it for possible rollback.
                # Note, this is not perfect because it does not recurse through
                # nested structures to get an exact diff, but it ensures that
                # we track only fields that are valid in the JSON schema
                updated_fields = u.value_diff(current.to_dict(), template)

                # Always attempt to update.  Since the template value is a
                # combination of JSON and config values, there is no useful
                # timestamp we can use to skip an update.
                # If sqlalchemy determines no change in fields, it will not
                # mark it as updated.
                try:
                    template = conductor.API.node_group_template_update(
                        ctx, current['id'], template, ignore_prot_on_def=True)
                except Exception as e:
                    LOG.warning(
                        _LW("Update of node group template {info} "
                            "failed, {reason}").format(
                                info=u.name_and_id(current), reason=e))
                    raise Handled()

                if template['updated_at'] != current['updated_at']:
                    ng_info["updated"].append((template, updated_fields))
                    LOG.info(
                        _LI("Updated node group template {info} "
                            "from {path}").format(info=u.name_and_id(template),
                                                  path=ng["path"]))
                else:
                    LOG.debug("No change to node group template {info} "
                              "from {path}".format(info=u.name_and_id(current),
                                                   path=ng['path']))
            else:
                template['is_default'] = True
                try:
                    template = conductor.API.node_group_template_create(
                        ctx, template)
                except Exception as e:
                    LOG.warning(
                        _LW("Creation of node group template "
                            "from {path} failed, {reason}").format(
                                path=ng['path'], reason=e))
                    raise Handled()

                ng_info["created"].append(template)
                LOG.info(
                    _LI("Created node group template {info} "
                        "from {path}").format(info=u.name_and_id(template),
                                              path=ng["path"]))

            # For the purposes of substitution we need a dict of id by name
            ng_info["ids"][template['name']] = template['id']

    except Handled:
        ng_info, error = do_reversals(ng_info)

    except Exception as e:
        LOG.warning(
            _LW("Unhandled exception while processing "
                "node group templates, {reason}").format(reason=e))
        ng_info, error = do_reversals(ng_info)

    return ng_info, error