-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secrets #840
Secrets #840
Conversation
* Finish secret hook tool calls, * Create secret add/get methods, * mods to accomadate spec evolution * Add in secret-event creation plumbing
The idea is to implement the secret hook tools in the testing backend as normal, but to have this pseudo-secret object that represents the juju secret semantics - e.g. tracking which units are on which revisions, whether a secret is expired, etc. This allows a test writer to do things like force-expire a secret at a desired point in time and then see how a charm reacts to it in various hook calls. Or to control the contents or access granting of a secret that is being consumed, and not explicitly controlled by the charm being tested.
This is exciting stuff @PietroPasotti! |
@sed-i not yet I'm afraid, the coming weeks while I wait for some juju bugs to be fixed and the implementation on their side to settle, I'll get working on the documentation. |
Pre-review comment: it'd be great to fix the formatting and tests before going too much further. I'm also getting errors when running
|
Will do it first thing tomorrow.
Will look into that, didn't notice. |
acc8e96
to
230116b
Compare
@sed-i I started working on some docs: https://discourse.charmhub.io/t/secret-events/7191 |
230116b
to
04a8b84
Compare
04a8b84
to
a022e06
Compare
I was about to close for the day when I realized that I'd forgotten to add a bunch of optional 'label' args to all sorts of Secret.remove/revoke etc methods, to be used if an ID is not provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not reviewed the ops/testing.py
or test/test_secrets.py
changes, but the rest of this looks good to me now. Nice work!
ops/model.py
Outdated
|
||
|
||
class SecretRotateValueError(SecretsError): | ||
"""Raised when one attempts to create a secret with a bad `rotate` value.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also check that we cannot create a secret with an expiry time in the past
ops/model.py
Outdated
meta=True) | ||
meta = typing.cast('_SecretGetMetadataDict', meta) | ||
|
||
except SecretOwnershipError: # let other types raise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not be using "programme by exception"
ops/model.py
Outdated
label = metadata.get('label') | ||
revision = int(metadata.get('revision')) | ||
return Secret(self._backend, secret_id, label=label, | ||
revision=revision, is_owned_by_this_unit=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I keep thinking "is owned by this unit" isn't quite right. In the case of the secret being owned by the application, the leader unit is allowed to manage the secret, but it doesn't own it.
Would we be better talking in terms of "managed_by_this_unit"?
ops/model.py
Outdated
... expiration=datetime.datetime(day=23, year=2045, month=12)) | ||
""" | ||
if not self._backend._hook_is_running: # noqa | ||
raise RuntimeError("This method is meant to be called from charm code only; " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a standard error message used by the OF? Is there a const somewhere?
ops/model.py
Outdated
"""The revision number for this secret. | ||
|
||
This will only be visible to the owner of the secret. | ||
Secret consumers will get ``None``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we need 2 classes:
Secret (for owners)
SecretContent (for consumers, returned from secret_get).
It seems like a suboptimal charmer experience to have to "know" what apis work and which don't.
A consumer will always only get the content. The owner always gets the full secret.
ops/model.py
Outdated
# fixme: ATM you can't secret-set without content (e.g. to only update the label), | ||
# but that is a bug in juju. | ||
# when that is fixed, `secret-set [id] --label X` will be valid. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixed now
ops/model.py
Outdated
|
||
def _validate_ownership(self, operation_name: str, | ||
should_own: bool = True): | ||
owns = self._is_owned_by_this_unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So checking - this "is owned" value is set if the current unit is the leader (for app owned secrets)?
ops/model.py
Outdated
raise TypeError( | ||
'cannot {} secret {} to a unit or application ' | ||
'target without specifying a relation as its scope'.format(operation, self)) | ||
if relation and isinstance(target, Application) and relation.app is not target: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Target application should come from the "remote application" property of the relation right? So we can never get this error?
ops/model.py
Outdated
operation_name, self)) | ||
if not should_own and owns: | ||
raise SecretOwnershipError( | ||
'Cannot {} secret {!r} as an owner. Only consumers can do that.'.format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remind me, when would we get this?
All this logic here is a bit convoluted and would be much simpler if we had separate classes for owners and consumers.
Tests and testing harness broken right now
This PR is getting too messy -- many commits over a long period of time, and many commits to main since the branch was created. Going to clean things up by deleting this branch and recreating on a new PR without the test harness for now. |
Based on canonical#840 with rework for the new API design and simplifications.
NOTE: new PR is #861. Note that if you're building charms, you'll need to update your branch to
benhoyt/operator@secrets
, so update your charm'srequirements.txt
to the following:ops wrappers for Juju Secrets (3.0.53.0.2+)
QA steps
A couple of tester/demo charms that can be deployed to try the functionality out:
https://github.com/PietroPasotti/secrets-demo-charms
Documentation changes
Added:
Bug reference
#836
Changelog
Added support for juju secrets.