-
Notifications
You must be signed in to change notification settings - Fork 121
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
feat: ops eval hook #1450
base: main
Are you sure you want to change the base?
feat: ops eval hook #1450
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
import subprocess | ||
import sys | ||
import warnings | ||
from optparse import Option | ||
from pathlib import Path | ||
from typing import Any, Dict, List, Optional, Tuple, Type, Union, cast | ||
|
||
|
@@ -32,6 +33,7 @@ | |
from ops.log import setup_root_logging | ||
|
||
CHARM_STATE_FILE = '.unit-state.db' | ||
CHARM_EVAL_EXPR_ENVVAR = 'CHARM_EVAL_EXPR' | ||
|
||
|
||
logger = logging.getLogger() | ||
|
@@ -523,15 +525,43 @@ def _commit(self): | |
"""Commit the framework and gracefully teardown.""" | ||
self.framework.commit() | ||
|
||
def _eval(self, expr: str): | ||
"""Eval an expression in the context of the charm and print the result to stdout.""" | ||
import json | ||
|
||
globs = {'self': self.charm, 'ops': ops, 'json': json} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel a slippery slope here: start with self, add ops, then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I agree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to be fair, jhack also has a sister command, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eval is mostly for inspection, not so much mutation. json felt like a universal, low-barrier addition. Yaml I wouldn't object to, but pathlib, os, operator feel too much. It's not about allowing you to golf complex operations into a string, it's about inspecting live data |
||
try: | ||
globs = {'self': self.charm, 'ops': ops, 'json': json} | ||
out = eval(expr, globs) | ||
except Exception: | ||
logger.exception( | ||
f'failure evaluating expression {expr!r} ' f'given available globs ({globs})' | ||
) | ||
return | ||
logger.debug(f'expression {expr!r} evaluated to {out!r}') | ||
print(out) | ||
|
||
def run(self): | ||
"""Emit and then commit the framework.""" | ||
try: | ||
if eval_expr := _is_eval_set(): | ||
return self._eval(eval_expr) | ||
self._emit() | ||
self._commit() | ||
finally: | ||
self.framework.close() | ||
|
||
|
||
def _is_eval_set() -> Optional[str]: | ||
"""Return the value of the `CHARM_EVAL_EXPR_ENVVAR` envvar, if set. | ||
|
||
This allows the admin to run, for example, | ||
`CHARM_EVAL_EXPR="self.foo()" juju exec mycharm/0` | ||
and see the result printed to stdout. | ||
""" | ||
return os.getenv(CHARM_EVAL_EXPR_ENVVAR) | ||
|
||
|
||
def main(charm_class: Type[ops.charm.CharmBase], use_juju_for_storage: Optional[bool] = None): | ||
"""Set up the charm and dispatch the observed event. | ||
|
||
|
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.
OT: unused, afaics