Skip to content

Commit

Permalink
[resotocore][feat] Support aliases for app run <app_name> (#1604)
Browse files Browse the repository at this point in the history
  • Loading branch information
meln1k committed May 26, 2023
1 parent 2cdf11f commit 19dd08c
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 141 deletions.
6 changes: 4 additions & 2 deletions resotocore/resotocore/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from resotocore.analytics.recurrent_events import emit_recurrent_events
from resotocore.cli.cli import CLIService
from resotocore.cli.command import alias_names, all_commands
from resotocore.cli.model import CLIDependencies
from resotocore.cli.dependencies import CLIDependencies
from resotocore.config.config_handler_service import ConfigHandlerService
from resotocore.config.config_override_service import ConfigOverrideService, model_from_db, override_config_for_startup
from resotocore.config.core_config_handler import CoreConfigHandler
Expand Down Expand Up @@ -184,7 +184,9 @@ def with_config(
cli_deps.extend(task_handler=task_handler, inspector=inspector)
infra_apps_runtime = LocalResotocoreAppRuntime(cli)
cli_deps.extend(infra_apps_runtime=infra_apps_runtime)
infra_apps_package_manager = PackageManager(db.package_entity_db, config_handler)
infra_apps_package_manager = PackageManager(
db.package_entity_db, config_handler, cli.register_alias_template, cli.unregister_alias_template
)
cli_deps.extend(infra_apps_package_manager=infra_apps_package_manager)
graph_manager = GraphManager(db, config.snapshots, core_config_handler, task_handler)
cli_deps.extend(graph_manager=graph_manager)
Expand Down
23 changes: 14 additions & 9 deletions resotocore/resotocore/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,20 @@
ExecutableCommand,
ParsedCommandLine,
CLICommand,
CLIDependencies,
InternalPart,
CLIContext,
CLI,
EmptyContext,
CLISource,
NoTerminalOutput,
OutputTransformer,
PreserveOutputFormat,
AliasTemplate,
ArgsInfo,
ArgInfo,
AliasTemplateParameter,
WorkerCustomCommand,
OutputTransformer,
PreserveOutputFormat,
)
from resotocore.cli.dependencies import CLIDependencies
from resotocore.console_renderer import ConsoleRenderer
from resotocore.error import CLIParseError
from resotocore.model.typed_model import class_fqn
Expand Down Expand Up @@ -258,15 +257,21 @@ def dependencies(self) -> CLIDependencies:
def alias_templates(self) -> Dict[str, AliasTemplate]:
return self.__alias_templates

def register_worker_custom_command(self, command: WorkerCustomCommand) -> None:
def register_alias_template(self, template: AliasTemplate) -> None:
"""
Called when a worker connects that introduces a custom command.
Called when something introduces a custom command.
The registered templated will always override any existing template.
"""
if command.name not in self.direct_commands and command.name not in self.alias_commands:
template = command.to_template()
if template.name not in self.direct_commands and template.name not in self.alias_commands:
self.alias_templates[template.name] = template

def unregister_alias_template(self, name: str) -> None:
"""
Called when something removes a custom command.
"""
if name in self.alias_templates:
del self.alias_templates[name]

async def start(self) -> None:
self.reaper = asyncio.create_task(self.reap_tasks())

Expand Down Expand Up @@ -523,7 +528,7 @@ def expand_alias(alias_cmd: ParsedCommand) -> List[ParsedCommand]:
alias: AliasTemplate = self.alias_templates[alias_cmd.cmd]
available: Dict[str, AliasTemplateParameter] = {p.name: p for p in alias.parameters}
props: Dict[str, JsonElement] = self.replacements(**{**self.cli_env, **context.env}) # type: ignore
props["args"] = alias_cmd.args
props["args"] = alias_cmd.args or ""
for p in alias.parameters:
props[p.name] = p.default
# only parse properties, if there are any declared
Expand Down
10 changes: 5 additions & 5 deletions resotocore/resotocore/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@
PreserveOutputFormat,
MediaType,
CLIFileRequirement,
CLIDependencies,
ParsedCommand,
NoTerminalOutput,
ArgsInfo,
ArgInfo,
)
from resotocore.cli.dependencies import CLIDependencies
from resotocore.cli.tip_of_the_day import SuggestionPolicy, SuggestionStrategy, get_suggestion_strategy
from resotocore.config import ConfigEntity
from resotocore.db.async_arangodb import AsyncCursor
Expand Down Expand Up @@ -3151,7 +3151,7 @@ def with_dependencies(model: Model) -> Stream:

# dependencies are not resolved directly (no async function is allowed here)
async def load_model() -> Model:
return await self.dependencies.model_handler.load_model(ctx.graph_name)
return await cast(CLIDependencies, self.dependencies).model_handler.load_model(ctx.graph_name)

dependencies = stream.call(load_model)
return stream.flatmap(dependencies, with_dependencies)
Expand Down Expand Up @@ -3274,7 +3274,7 @@ def with_dependencies(model: Model) -> Stream:
return self.send_to_queue_stream(stream.map(load, fn), result_handler, not ns.nowait)

async def load_model() -> Model:
return await self.dependencies.model_handler.load_model(ctx.graph_name)
return await cast(CLIDependencies, self.dependencies).model_handler.load_model(ctx.graph_name)

# dependencies are not resolved directly (no async function is allowed here)
dependencies = stream.call(load_model)
Expand Down Expand Up @@ -3921,7 +3921,7 @@ async def perform_request(e: JsonElement) -> int:
authuser, authpass = template.auth.split(":", 1) if template.auth else (None, None)
log.debug(f"Perform request with this template={template} and data={data}")
try:
async with self.dependencies.http_session.request(
async with cast(CLIDependencies, self.dependencies).http_session.request(
template.method,
template.url,
headers=template.headers,
Expand Down Expand Up @@ -4990,7 +4990,7 @@ async def apps_list() -> AsyncIterator[JsonElement]:
async def app_run(
in_stream: JsGen, app_name: InfraAppName, dry_run: bool, config: Optional[str]
) -> AsyncIterator[JsonElement]:
runtime = self.dependencies.infra_apps_runtime
runtime = cast(CLIDependencies, self.dependencies).infra_apps_runtime
manifest = await self.dependencies.infra_apps_package_manager.get_manifest(app_name)
if not manifest:
raise ValueError(f"App {app_name} is not installed.")
Expand Down
112 changes: 112 additions & 0 deletions resotocore/resotocore/cli/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from asyncio import Queue, Task
from typing import Optional, Any, Dict, Tuple

from aiohttp import ClientSession, TCPConnector

from resotocore.analytics import AnalyticsEventSender
from resotocore.config import ConfigHandler
from resotocore.core_config import CoreConfig
from resotocore.db.db_access import DbAccess
from resotocore.message_bus import MessageBus
from resotocore.model.model_handler import ModelHandler
from resotocore.query.template_expander import TemplateExpander
from resotocore.report import Inspector
from resotocore.task import TaskHandler
from resotocore.types import JsonElement
from resotocore.user import UserManagement
from resotocore.web.certificate_handler import CertificateHandler
from resotocore.worker_task_queue import WorkerTaskQueue
from resotocore.infra_apps.runtime import Runtime
from resotocore.infra_apps.package_manager import PackageManager
from resotocore.graph_manager.graph_manager import GraphManager
from resotocore.cli.model import CLIEngine


class CLIDependencies:
def __init__(self, **deps: Any) -> None:
self.lookup: Dict[str, Any] = deps

def extend(self, **deps: Any) -> "CLIDependencies":
self.lookup = {**self.lookup, **deps}
return self

@property
def config(self) -> CoreConfig:
return self.lookup["config"] # type: ignore

@property
def message_bus(self) -> MessageBus:
return self.lookup["message_bus"] # type:ignore

@property
def event_sender(self) -> AnalyticsEventSender:
return self.lookup["event_sender"] # type:ignore

@property
def db_access(self) -> DbAccess:
return self.lookup["db_access"] # type:ignore

@property
def model_handler(self) -> ModelHandler:
return self.lookup["model_handler"] # type:ignore

@property
def task_handler(self) -> TaskHandler:
return self.lookup["task_handler"] # type:ignore

@property
def worker_task_queue(self) -> WorkerTaskQueue:
return self.lookup["worker_task_queue"] # type:ignore

@property
def template_expander(self) -> TemplateExpander:
return self.lookup["template_expander"] # type:ignore

@property
def forked_tasks(self) -> Queue[Tuple[Task[JsonElement], str]]:
return self.lookup["forked_tasks"] # type:ignore

@property
def cli(self) -> CLIEngine:
return self.lookup["cli"] # type:ignore

@property
def config_handler(self) -> ConfigHandler:
return self.lookup["config_handler"] # type:ignore

@property
def cert_handler(self) -> CertificateHandler:
return self.lookup["cert_handler"] # type:ignore

@property
def inspector(self) -> Inspector:
return self.lookup["inspector"] # type:ignore

@property
def infra_apps_runtime(self) -> Runtime:
return self.lookup["infra_apps_runtime"] # type:ignore

@property
def infra_apps_package_manager(self) -> PackageManager:
return self.lookup["infra_apps_package_manager"] # type:ignore

@property
def user_management(self) -> UserManagement:
return self.lookup["user_management"] # type:ignore

@property
def graph_manager(self) -> GraphManager:
return self.lookup["graph_manager"] # type:ignore

@property
def http_session(self) -> ClientSession:
session: Optional[ClientSession] = self.lookup.get("http_session")
if not session:
connector = TCPConnector(limit=0, ssl=False, ttl_dns_cache=300)
session = ClientSession(connector=connector)
self.lookup["http_session"] = session
return session

async def stop(self) -> None:
if "http_session" in self.lookup:
await self.http_session.close()
Loading

0 comments on commit 19dd08c

Please sign in to comment.