Skip to content

Commit

Permalink
plugins now target the api endpoint in their homepage
Browse files Browse the repository at this point in the history
  • Loading branch information
CamDavidsonPilon committed Dec 24, 2024
1 parent 888efc3 commit 6025268
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 22 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
- [ ] test self-test
- [ ] check back edits to stirring calibration
- [ ] changes to settings api in unit_api
- [ ] logs page
- new table for historical assignments
- plugins page has dropdown to select the unit

### 24.12.10
- Hotfix for UI settings bug
Expand Down
30 changes: 16 additions & 14 deletions pioreactor/actions/leader/experiment_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from pioreactor.whoami import get_unit_name
from pioreactor.whoami import is_testing_env

bool_expression = str | bool
BoolExpression = str | bool
Env = dict[str, Any]

STRICT_EXPRESSION_PATTERN = r"^\${{(.*?)}}$"
Expand Down Expand Up @@ -90,7 +90,7 @@ def evaluate_log_message(message: str, env: dict) -> str:
return result_string


def evaluate_bool_expression(bool_expression: bool_expression, env: dict) -> bool:
def evaluate_bool_expression(bool_expression: BoolExpression, env: dict) -> bool:
from pioreactor.experiment_profiles.parser import parse_profile_expression_to_bool

if isinstance(bool_expression, bool):
Expand All @@ -103,7 +103,7 @@ def evaluate_bool_expression(bool_expression: bool_expression, env: dict) -> boo
return parse_profile_expression_to_bool(bool_expression, env=env)


def check_syntax_of_bool_expression(bool_expression: bool_expression) -> bool:
def check_syntax_of_bool_expression(bool_expression: BoolExpression) -> bool:
from pioreactor.experiment_profiles.parser import check_syntax

if isinstance(bool_expression, bool):
Expand Down Expand Up @@ -320,11 +320,11 @@ def when(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
condition: bool_expression,
condition: BoolExpression,
when_action: struct.When,
actions: list[struct.Action],
schedule: scheduler,
Expand Down Expand Up @@ -393,12 +393,12 @@ def repeat(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
repeat_action: struct.Repeat,
while_: Optional[bool_expression],
while_: Optional[BoolExpression],
repeat_every_hours: float,
max_hours: Optional[float],
actions: list[struct.BasicAction],
Expand Down Expand Up @@ -484,7 +484,7 @@ def log(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -517,7 +517,7 @@ def start_job(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -559,7 +559,7 @@ def pause_job(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -595,7 +595,7 @@ def resume_job(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -632,7 +632,7 @@ def stop_job(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -668,7 +668,7 @@ def update_job(
client: Client,
job_name: str,
dry_run: bool,
if_: Optional[bool_expression],
if_: Optional[BoolExpression],
env: dict,
logger: CustomLogger,
elapsed_seconds_func: Callable[[], float],
Expand Down Expand Up @@ -814,7 +814,9 @@ def execute_experiment_profile(profile_filename: str, experiment: str, dry_run:
unit = get_unit_name()
action_name = "experiment_profile"
logger = create_logger(action_name, unit=unit, experiment=experiment)
with managed_lifecycle(unit, experiment, action_name, ignore_is_active_state=True) as state:
with managed_lifecycle(
unit, experiment, action_name, ignore_is_active_state=True, is_long_running_job=True
) as state:
try:
profile = load_and_verify_profile(profile_filename)
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion pioreactor/background_jobs/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def pretty_version(info: tuple) -> str:
# we manually run a self_check outside of a thread first, as if there are
# problems detected, we may want to block and not let the job continue.
self.self_check_thread = RepeatedTimer(
4 * 60 * 60, self.self_checks, job_name=self.job_name, run_immediately=True, logger=self.logger
12 * 60 * 60, self.self_checks, job_name=self.job_name, run_immediately=True, logger=self.logger
).start()

self.add_pre_button_callback(self._republish_state)
Expand Down
10 changes: 9 additions & 1 deletion pioreactor/plugin_management/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
from .uninstall_plugin import click_uninstall_plugin
from .utils import discover_plugins_in_entry_points
from .utils import discover_plugins_in_local_folder
from pioreactor import pubsub
from pioreactor.utils import networking
from pioreactor.whoami import get_unit_name

"""
How do plugins work? There are a few patterns we use to "register" plugins with the core app.
Expand Down Expand Up @@ -56,6 +59,11 @@ class Plugin(Struct):
source: str


def get_plugin_api_url(py_file: str) -> str:
endpoint = f"/unit_api/plugins/installed/{py_file}"
return pubsub.create_webserver_path(networking.resolve_to_address(get_unit_name()), endpoint)


def get_plugins() -> dict[str, Plugin]:
"""
This function is really time consuming...
Expand Down Expand Up @@ -106,7 +114,7 @@ def get_plugins() -> dict[str, Plugin]:
module,
getattr(module, "__plugin_summary__", BLANK),
getattr(module, "__plugin_version__", BLANK),
getattr(module, "__plugin_homepage__", BLANK),
getattr(module, "__plugin_homepage__", get_plugin_api_url(py_file.name)),
getattr(module, "__plugin_author__", BLANK),
f"plugins/{py_file.name}",
)
Expand Down
6 changes: 1 addition & 5 deletions pioreactor/pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,11 @@ def create_webserver_path(address: str, endpoint: str) -> str:
# Most commonly, address can be an mdns name (test.local), or an IP address.
port = config.getint("ui", "port", fallback=80)
proto = config.get("ui", "proto", fallback="http")
endpoint = conform_and_validate_api_endpoint(endpoint)
return f"{proto}://{address}:{port}/{endpoint}"


def get_from(address: str, endpoint: str, **kwargs) -> mureq.Response:
endpoint = conform_and_validate_api_endpoint(endpoint)
return mureq.get(create_webserver_path(address, endpoint), **kwargs)


Expand All @@ -377,7 +377,6 @@ def get_from_leader(endpoint: str, **kwargs) -> mureq.Response:
def put_into(
address: str, endpoint: str, body: bytes | None = None, json: dict | Struct | None = None, **kwargs
) -> mureq.Response:
endpoint = conform_and_validate_api_endpoint(endpoint)
return mureq.put(create_webserver_path(address, endpoint), body=body, json=json, **kwargs)


Expand All @@ -390,7 +389,6 @@ def put_into_leader(
def patch_into(
address: str, endpoint: str, body: bytes | None = None, json: dict | Struct | None = None, **kwargs
) -> mureq.Response:
endpoint = conform_and_validate_api_endpoint(endpoint)
return mureq.patch(create_webserver_path(address, endpoint), body=body, json=json, **kwargs)


Expand All @@ -403,7 +401,6 @@ def patch_into_leader(
def post_into(
address: str, endpoint: str, body: bytes | None = None, json: dict | Struct | None = None, **kwargs
) -> mureq.Response:
endpoint = conform_and_validate_api_endpoint(endpoint)
return mureq.post(create_webserver_path(address, endpoint), body=body, json=json, **kwargs)


Expand All @@ -414,7 +411,6 @@ def post_into_leader(


def delete_from(address: str, endpoint: str, **kwargs) -> mureq.Response:
endpoint = conform_and_validate_api_endpoint(endpoint)
return mureq.delete(create_webserver_path(address, endpoint), **kwargs)


Expand Down
4 changes: 3 additions & 1 deletion pioreactor/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def __init__(
exit_on_mqtt_disconnect: bool = False,
mqtt_client_kwargs: dict | None = None,
ignore_is_active_state=False, # hack and kinda gross
is_long_running_job=False,
source: str = "app",
job_source: str | None = None,
) -> None:
Expand All @@ -163,6 +164,7 @@ def __init__(
self.state = "init"
self.exit_event = Event()
self._source = source
self.is_long_running_job = is_long_running_job
self._job_source = job_source or os.environ.get("JOB_SOURCE") or "user"

last_will = {
Expand Down Expand Up @@ -215,7 +217,7 @@ def __enter__(self) -> managed_lifecycle:
self._job_source,
getpid(),
"", # TODO: why is leader string empty? perf?
False,
self.is_long_running_job,
)

self.state = "ready"
Expand Down

0 comments on commit 6025268

Please sign in to comment.