Skip to content

Commit

Permalink
Merge pull request #214 from rtCamp/feat/restart-command
Browse files Browse the repository at this point in the history
feat: `restart` command
  • Loading branch information
Xieyt authored Jun 28, 2024
2 parents 8a64966 + 6964076 commit 1d13a3e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 49 deletions.
43 changes: 42 additions & 1 deletion frappe_manager/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,10 @@ def update(
choices=['yes', 'no'],
)
if should_restart == 'yes':
bench.restart_frappe_server()
# bench.restart_frappe_server()
richprint.change_head("Restarting frappe server")
bench.restart_supervisor_service('frappe')
richprint.print("Restarted frappe server")

if bench_config_save:
bench.save_bench_config()
Expand All @@ -641,3 +644,41 @@ def reset(
verbose = ctx.obj['verbose']
bench = Bench.get_object(benchname, services_manager)
bench.reset(admin_pass)


@app.command()
def restart(
ctx: typer.Context,
benchname: Annotated[
Optional[str],
typer.Argument(
help="Name of the bench.", autocompletion=sites_autocompletion_callback, callback=sitename_callback
),
] = None,
web: Annotated[
bool,
typer.Option(help="Restart web service i.e socketio and frappe server."),
] = True,
workers: Annotated[
bool,
typer.Option(help="Restart worker services i.e schedule and all workers."),
] = True,
redis: Annotated[
bool,
typer.Option(help="Restart redis services."),
] = False,
):
"""Restart bench services."""

services_manager = ctx.obj["services"]
verbose = ctx.obj['verbose']
bench = Bench.get_object(benchname, services_manager)

if web:
bench.restart_web_containers_services()

if workers:
bench.restart_workers_containers_services()

if redis:
bench.restart_redis_services_containers()
2 changes: 1 addition & 1 deletion frappe_manager/compose_project/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(

class DockerComposeProjectFailedToRestartError(Exception):
def __init__(
self, compose_path: Path, services: List[str], message='Failed to pull compose services {} images.'
self, compose_path: Path, services: List[str], message='Failed to restart compose services {} images.'
) -> None:
self.compose_path = compose_path
self.services = services
Expand Down
55 changes: 30 additions & 25 deletions frappe_manager/site_manager/bench_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from frappe_manager import STABLE_APP_BRANCH_MAPPING_LIST
from frappe_manager.compose_project.compose_project import ComposeProject
from frappe_manager.docker_wrapper.DockerException import DockerException
from frappe_manager.docker_wrapper.subprocess_output import SubprocessOutput
from frappe_manager.site_manager.site_exceptions import (
Expand Down Expand Up @@ -47,7 +48,7 @@ def create_fm_bench(self):

self.bench_install_apps(self.bench.bench_config.apps_list)

self.frappe_container_run(
self.container_run(
"rm -rf /workspace/frappe-bench/archived",
BenchOperationException(self.bench.name, "Failed to remove /workspace/frappe-bench/archived directory."),
)
Expand All @@ -72,18 +73,16 @@ def create_bench_site(self):

new_site_command = " ".join(new_site_command)

self.frappe_container_run(
new_site_command, raise_exception_obj=BenchOperationBenchSiteCreateFailed(self.bench.name)
)
self.container_run(new_site_command, raise_exception_obj=BenchOperationBenchSiteCreateFailed(self.bench.name))

self.frappe_container_run(
self.container_run(
" ".join(self.bench_cli_cmd + [f"use {self.bench.name}"]),
raise_exception_obj=BenchOperationException(
self.bench.name, f"Failed to set {self.bench.name} as default site."
),
)

self.frappe_container_run(
self.container_run(
" ".join(self.bench_cli_cmd + [f"--site {self.bench.name} scheduler enable"]),
raise_exception_obj=BenchOperationException(
self.bench.name, f"Failed to enable {self.bench.name}'s scheduler."
Expand All @@ -103,23 +102,31 @@ def is_required_services_available(self):
if output.combined:
richprint.print(output.combined[-1].replace('wait-for-it: ', ''), highlight=False)

def frappe_container_run(
def container_run(
self,
command: str,
raise_exception_obj: Optional[BenchOperationException] = None,
capture_output: bool = False,
user: str = "frappe",
workdir="/workspace/frappe-bench",
service: str = 'frappe',
compose_project_obj: Optional[ComposeProject] = None,
):

if compose_project_obj:
compose_project: ComposeProject = compose_project_obj
else:
compose_project: ComposeProject = self.bench.compose_project

try:
if capture_output:
output: SubprocessOutput = self.bench.compose_project.docker.compose.exec(
service="frappe", command=command, user=user, workdir=workdir, stream=not capture_output
output: SubprocessOutput = compose_project.docker.compose.exec(
service=service, command=command, user=user, workdir=workdir, stream=not capture_output
)
return output
else:
output: Iterable[Tuple[str, bytes]] = self.bench.compose_project.docker.compose.exec(
service="frappe", command=command, workdir=workdir, user=user, stream=not capture_output
output: Iterable[Tuple[str, bytes]] = compose_project.docker.compose.exec(
service=service, command=command, workdir=workdir, user=user, stream=not capture_output
)
richprint.live_lines(output)

Expand All @@ -143,7 +150,7 @@ def change_frappeverse_prebaked_app_branch(self, app: str, branch: str):
bench_name=self.bench.name, app=app, branch=self.bench.bench_config.frappe_branch
)

self.frappe_container_run(command=change_frappe_branch_command, raise_exception_obj=exception)
self.container_run(command=change_frappe_branch_command, raise_exception_obj=exception)

richprint.print(f"Configured {app} app's branch -> {self.bench.bench_config.frappe_branch}")

Expand All @@ -163,7 +170,7 @@ def setup_supervisor(self, force: bool = False):
bench_setup_supervisor_exception = BenchOperationException(
self.bench.name, "Failed to configure supervisor."
)
self.frappe_container_run(bench_setup_supervisor_command, bench_setup_supervisor_exception)
self.container_run(bench_setup_supervisor_command, bench_setup_supervisor_exception)
self.split_supervisor_config()
richprint.print("Configured supervisor configs")

Expand Down Expand Up @@ -196,12 +203,10 @@ def split_supervisor_config(self):
self.bench.logger.info(f"Split supervisor conf {section_name} => {file_name}")

def setup_frappe_server_config(self):
bench_serve_help_output: Optional[SubprocessOutput] = self.frappe_container_run(
bench_serve_help_output: Optional[SubprocessOutput] = self.container_run(
" ".join(self.bench_cli_cmd + ["serve --help"]), capture_output=True
)
bench_dev_server_script_output = self.frappe_container_run(
"cat /opt/user/bench-dev-server", capture_output=True
)
bench_dev_server_script_output = self.container_run("cat /opt/user/bench-dev-server", capture_output=True)
import re

if "host" in " ".join(bench_serve_help_output.combined):
Expand All @@ -213,8 +218,8 @@ def setup_frappe_server_config(self):
r"--port \d+", "--port 80", " ".join(bench_dev_server_script_output.combined)
)

self.frappe_container_run(f'echo "{new_bench_dev_server_script}" > /opt/user/bench-dev-server.sh')
self.frappe_container_run("chmod +x /opt/user/bench-dev-server.sh", user='root')
self.container_run(f'echo "{new_bench_dev_server_script}" > /opt/user/bench-dev-server.sh')
self.container_run("chmod +x /opt/user/bench-dev-server.sh", user='root')

def bench_install_apps(self, apps_lists, already_installed_apps: Dict = STABLE_APP_BRANCH_MAPPING_LIST):
to_install_apps = [x["app"] for x in apps_lists]
Expand Down Expand Up @@ -274,7 +279,7 @@ def bench_build(self, app_list: Optional[List[str]] = None):
build_exception = BenchOperationBenchBuildFailed(bench_name=self.bench.name, apps=app_list)

build_cmd = " ".join(build_cmd)
self.frappe_container_run(build_cmd, build_exception)
self.container_run(build_cmd, build_exception)

def bench_install_app_env(
self, app: str, branch: Optional[str] = None, overwrite: bool = True, skip_assets: bool = False
Expand All @@ -289,7 +294,7 @@ def bench_install_app_env(
app_install_env_command = " ".join(app_install_env_command)
app_install_exception = BenchOperationBenchInstallAppInPythonEnvFailed(bench_name=self.bench.name, app_name=app)

self.frappe_container_run(
self.container_run(
app_install_env_command,
raise_exception_obj=app_install_exception,
)
Expand All @@ -304,7 +309,7 @@ def bench_rm_app_env(self, app: str, no_backup: bool = True, force: bool = True)

app_rm_env_command = " ".join(app_rm_env_command)

self.frappe_container_run(
self.container_run(
app_rm_env_command,
raise_exception_obj=BenchOperationBenchRemoveAppFromPythonEnvFailed(
bench_name=self.bench.name, app_name=app
Expand All @@ -316,7 +321,7 @@ def bench_install_app_site(self, app: str):
app_install_site_command += ["install-app", app]
app_install_site_command = " ".join(app_install_site_command)

self.frappe_container_run(
self.container_run(
app_install_site_command,
raise_exception_obj=BenchOperationBenchAppInSiteFailed(bench_name=self.bench.name, app_name=app),
)
Expand All @@ -326,7 +331,7 @@ def is_bench_site_exists(self, bench_site_name: str):
return site_path.exists()

def wait_for_required_service(self, host: str, port: int, timeout: int = 120):
return self.frappe_container_run(
return self.container_run(
f"wait-for-it -t {timeout} {host}:{port}",
raise_exception_obj=BenchOperationWaitForRequiredServiceFailed(
bench_name=self.bench.name, host=host, port=port, timeout=timeout
Expand Down Expand Up @@ -375,7 +380,7 @@ def reset_bench_site(self, admin_password: str):

reset_bench_site_command = " ".join(reset_bench_site_command)

self.frappe_container_run(
self.container_run(
reset_bench_site_command,
raise_exception_obj=BenchOperationException(
bench_name=self.bench.name, message=f'Failed to reset bench site {self.bench.name}.'
Expand Down
94 changes: 72 additions & 22 deletions frappe_manager/site_manager/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ def sync_bench_config_configuration(self):
self.admin_tools.disable()
richprint.print("Disabled Admin-tools.")

self.restart_frappe_server()
richprint.change_head("Restarting frappe server")
self.restart_supervisor_service('frappe')
richprint.print("Restarted frappe server")

def save_bench_config(self):
richprint.change_head("Saving bench config changes")
Expand All @@ -163,14 +165,6 @@ def save_bench_config(self):
def exists(self):
return self.path.exists()

@property
def frappe_container_name_as_hex(self) -> str:
"""
Returns the hexadecimal representation of the frappe container name.
"""
container_name = self.compose_project.compose_file_manager.get_container_names()
return container_name["frappe"].encode().hex()

def create(self, is_template_bench: bool = False):
"""
Creates a new bench using the provided template inputs.
Expand Down Expand Up @@ -861,8 +855,6 @@ def logs(self, follow: bool, service: Optional[SiteServicesEnum] = None):

except KeyboardInterrupt:
richprint.stdout.print("Detected CTRL+C. Exiting..")
# for log_file in log_files:
# log_file.close()

def attach_to_bench(self, user: str, extensions: List[str], workdir: str, debugger: bool = False):
"""
Expand All @@ -883,7 +875,8 @@ def attach_to_bench(self, user: str, extensions: List[str], workdir: str, debugg
# TODO todo this should be exception
richprint.exit("Visual Studio Code binary i.e 'code' is not accessible via cli.")

container_hex = self.frappe_container_name_as_hex
container_name = self.compose_project.compose_file_manager.get_container_names()
container_hex = container_name["frappe"].encode().hex()

vscode_cmd = shlex.join(
[
Expand Down Expand Up @@ -1058,16 +1051,6 @@ def sync_admin_tools_compose(self):
restart_required = self.admin_tools.enable(force_recreate_container=True)
return restart_required

def restart_frappe_server(self):
richprint.change_head("Restarting frappe server")
restart_command = 'supervisorctl -c /opt/user/supervisord.conf restart all'

try:
self.compose_project.docker.compose.exec('frappe', restart_command, user='frappe', stream=False)
except DockerException as e:
raise BenchException("frappe", "Faild to restart frappe server.")
richprint.print("Restarted frappe server.")

def frappe_service_run_command(self, command: str):
try:
self.compose_project.docker.compose.exec('frappe', command, user='frappe', stream=False)
Expand Down Expand Up @@ -1210,3 +1193,70 @@ def reset(self, admin_password: Optional[str] = None):
self.set_bench_site_config({'admin_password': admin_pass})

richprint.print(f"Reset bench site {self.name}")

def restart_supervisor_service(self, service: str, compose_project_obj: Optional[ComposeProject] = None):
restart_supervisor_command = 'supervisorctl -c /opt/user/supervisord.conf restart all'
exception = BenchOperationException(self.name, message=f'Failed to restart supervisor for {service} service')

if not compose_project_obj:
compose_project_obj = self.compose_project

if not compose_project_obj.is_service_running(service):
richprint.error(text=f'Service [blue]{service}[/blue] not running.')
return False

self.benchops.container_run(
command=restart_supervisor_command,
raise_exception_obj=exception,
service=service,
compose_project_obj=compose_project_obj,
)
return True

def restart_web_containers_services(self):
"""Restarts frappe server and socketio containers"""

# restart frappe server and socketio
web_services = [
SiteServicesEnum.frappe.value,
SiteServicesEnum.socketio.value,
]

restart_supervisor_command = 'supervisorctl -c /opt/user/supervisord.conf restart all'

for service in web_services:
richprint.change_head(f"Restarting web services - {service}")
is_restarted = self.restart_supervisor_service(service)
if is_restarted:
richprint.print(f"Restarted web services - {service}")

def restart_redis_services_containers(self):
"""Restarts redis containers"""

redis_services = [
SiteServicesEnum.redis_cache.value,
SiteServicesEnum.redis_queue.value,
SiteServicesEnum.redis_socketio.value,
]
richprint.change_head(f"Restarting redis services - {' '.join(redis_services)}")
self.compose_project.restart_service(services=redis_services)
richprint.print(f"Restarted redis services - {' '.join(redis_services)}")

def restart_workers_containers_services(self):
"""Restarts workers and schedule containers"""

# restart schduler
worker_services = [SiteServicesEnum.schedule.value]

for service in worker_services:
richprint.change_head(f"Restarting worker service - {service}")
is_restarted = self.restart_supervisor_service(service)
if is_restarted:
richprint.print(f"Restarted worker services - {service}")

worker_services = self.workers.compose_project.compose_file_manager.get_services_list()
for service in worker_services:
richprint.change_head(f"Restarting worker service - {service}")
is_restarted = self.restart_supervisor_service(service, compose_project_obj=self.workers.compose_project)
if is_restarted:
richprint.print(f"Restarted worker services - {service}")
12 changes: 12 additions & 0 deletions frappe_manager/utils/examples.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,5 +271,17 @@
"code": ""
}
]
},
"restart": {
"examples": [
{
"desc": "Restart web services only",
"code": "--web"
},
{
"desc": "Restart workers and web services",
"code": "--web --workers"
}
]
}
}

0 comments on commit 1d13a3e

Please sign in to comment.