Skip to content

mysql lib can only set a single secret #367

@tonyandrewmeyer

Description

@tonyandrewmeyer

Steps to reproduce

This charm demonstrates the issue:

#!/usr/bin/env python3

import logging
import ops
from charms.data_platform_libs.v0.data_secrets import SecretCache, generate_secret_label, SecretAlreadyExistsError

logger = logging.getLogger(__name__)

class MysqlOperator348BugCharm(ops.CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        self.secrets = SecretCache(self)
        self.framework.observe(self.on.install, self._on_install)

    def _on_install(self, event: ops.InstallEvent):
        secret1 = {"name1": "abcdefgh"}
        label1 = generate_secret_label(self, "app")
        self.secrets.add(label1, secret1, "app")
        secret2 = {"name2": "password"}
        label2 = generate_secret_label(self, "app")
        logger.info(f"label1: {label1}, label2: {label2}, secrets: {self.secrets._secrets}")
        try:
            self.secrets.add(label2, secret2, "app")
        except SecretAlreadyExistsError as e:
            logger.error("Failed to add second secret: %s", e)
        else:
            logger.info(f"label1: {label1}, label2: {label2}, secrets: {self.secrets._secrets}")

if __name__ == "__main__":  # pragma: nocover
    ops.main(MysqlOperator348BugCharm)  # type: ignore

Note that you need to have the main version of the data_platform_libs, not one from a charmcraft fetch.

Expected behavior

With the above charm, the first INFO logging line should look something like:

label1: something, label2: something-else, secrets: {'something': <...>}

And there should be a second one like:

label1: something, label2: something-else, secrets: {'something': <...>, 'something-else': <...>}

Actual behavior

With the above charm, the logging output is:

unit-secret-bug-0: 09:54:30 INFO unit.secret-bug/0.juju-log label1: secret-bug.app, label2: secret-bug.app, secrets: {'secret-bug.app': <charms.data_platform_libs.v0.data_secrets.CachedSecret object at 0x7f5da6ed24a0>}
unit-secret-bug-0: 09:54:30 ERROR unit.secret-bug/0.juju-log Failed to add second secret: Secret secret-bug.app already exists

The issue is that the generate_secret_label method in data_secrets.py takes the charm and the scope as arguments, and uses the charm's app name and the scope to form the label. The app name is obviously the same across the app, and the scope is either app or unit. This means that if you try to get a label for an app secret, you'll always get exactly the same string. This effectively means that the SecretCache system as used by mysql.py will only store a single app secret, because it believes that any secret is already in the cache after one is.

Versions

Operating system: Ubuntu 23.10

Juju CLI: 3.1.6-genericlinux-amd64

(Note that the code never gets to Juju in the problematic area).

Juju agent: 3.1.5

Charm revision: N/A

LXD: N/A

Log output

Juju debug log:

Copied above.

Additional context

This was introduced in #348. You can also see failing unit tests if you bump your ops requirement to 2.6.0 or higher (I haven't looked at exactly what changes there, but presumably some of the code starts exercising more of the secret support in ops).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working as expected

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions