Add back build log command to CLI (#2053)
This commit is contained in:
parent
a2e185cced
commit
23255d49d4
@ -544,7 +544,7 @@ def deploy(
|
||||
enabled_regions = pre_deploy_response.enabled_regions
|
||||
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to prepare deployment due to: {ex}")
|
||||
console.error(f"Unable to prepare deployment")
|
||||
raise typer.Exit(1) from ex
|
||||
|
||||
# The app prefix should not change during the time of preparation
|
||||
@ -572,7 +572,6 @@ def deploy(
|
||||
key = key_candidate
|
||||
|
||||
# Then CP needs to know the user's location, which requires user permission
|
||||
console.debug(f"{enabled_regions=}")
|
||||
while True:
|
||||
region_input = console.ask(
|
||||
"Region to deploy to. Enter to use default.",
|
||||
@ -669,10 +668,15 @@ def deploy(
|
||||
|
||||
console.print("Waiting for server to report progress ...")
|
||||
# Display the key events such as build, deploy, etc
|
||||
asyncio.get_event_loop().run_until_complete(
|
||||
server_report_deploy_success = asyncio.get_event_loop().run_until_complete(
|
||||
hosting.display_deploy_milestones(key, from_iso_timestamp=deploy_requested_at)
|
||||
)
|
||||
|
||||
if not server_report_deploy_success:
|
||||
console.error("Hosting server reports failure.")
|
||||
console.error(
|
||||
f"Check the server logs using `reflex deployments build-logs {key}`"
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
console.print("Waiting for the new deployment to come up")
|
||||
backend_up = frontend_up = False
|
||||
|
||||
@ -741,7 +745,7 @@ def list_deployments(
|
||||
try:
|
||||
deployments = hosting.list_deployments()
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to list deployments due to: {ex}")
|
||||
console.error(f"Unable to list deployments")
|
||||
raise typer.Exit(1) from ex
|
||||
|
||||
if as_json:
|
||||
@ -768,7 +772,7 @@ def delete_deployment(
|
||||
try:
|
||||
hosting.delete_deployment(key)
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to delete deployment due to: {ex}")
|
||||
console.error(f"Unable to delete deployment")
|
||||
raise typer.Exit(1) from ex
|
||||
console.print(f"Successfully deleted [ {key} ].")
|
||||
|
||||
@ -805,7 +809,7 @@ def get_deployment_status(
|
||||
table = list(frontend_status.values())
|
||||
console.print(tabulate([table], headers=headers))
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to get deployment status due to: {ex}")
|
||||
console.error(f"Unable to get deployment status")
|
||||
raise typer.Exit(1) from ex
|
||||
|
||||
|
||||
@ -822,7 +826,28 @@ def get_deployment_logs(
|
||||
try:
|
||||
asyncio.get_event_loop().run_until_complete(hosting.get_logs(key))
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to get deployment logs due to: {ex}")
|
||||
console.error(f"Unable to get deployment logs")
|
||||
raise typer.Exit(1) from ex
|
||||
|
||||
|
||||
@deployments_cli.command(name="build-logs")
|
||||
def get_deployment_build_logs(
|
||||
key: str = typer.Argument(..., help="The name of the deployment."),
|
||||
loglevel: constants.LogLevel = typer.Option(
|
||||
config.loglevel, help="The log level to use."
|
||||
),
|
||||
):
|
||||
"""Get the logs for a deployment."""
|
||||
console.set_log_level(loglevel)
|
||||
|
||||
console.print("Note: there is a few seconds delay for logs to be available.")
|
||||
try:
|
||||
# TODO: we need to find a way not to fetch logs
|
||||
# that match the deployed app name but not previously of a different owner
|
||||
# This should not happen often
|
||||
asyncio.run(hosting.get_logs(key, log_type=hosting.LogType.BUILD_LOG))
|
||||
except Exception as ex:
|
||||
console.error(f"Unable to get deployment logs")
|
||||
raise typer.Exit(1) from ex
|
||||
|
||||
|
||||
|
@ -44,7 +44,7 @@ DEPLOYMENT_LOGS_ENDPOINT = f'{config.cp_backend_url.replace("http", "ws")}/deplo
|
||||
# Expected server response time to new deployment request. In seconds.
|
||||
DEPLOYMENT_PICKUP_DELAY = 30
|
||||
# End of deployment workflow message. Used to determine if it is the last message from server.
|
||||
END_OF_DEPLOYMENT_MESSAGES = ["deploy success", "deploy failed"]
|
||||
END_OF_DEPLOYMENT_MESSAGES = ["deploy success"]
|
||||
# How many iterations to try and print the deployment event messages from server during deployment.
|
||||
DEPLOYMENT_EVENT_MESSAGES_RETRIES = 90
|
||||
# Timeout limit for http requests
|
||||
@ -93,7 +93,7 @@ def validate_token(token: str):
|
||||
response.raise_for_status()
|
||||
except httpx.RequestError as re:
|
||||
console.debug(f"Request to auth server failed due to {re}")
|
||||
raise Exception("request error") from re
|
||||
raise Exception(str(re)) from re
|
||||
except httpx.HTTPError as ex:
|
||||
console.debug(f"Unable to validate the token due to: {ex}")
|
||||
raise Exception("server error") from ex
|
||||
@ -307,22 +307,22 @@ def prepare_deploy(
|
||||
enabled_regions=response_json.get("enabled_regions"),
|
||||
)
|
||||
except httpx.RequestError as re:
|
||||
console.debug(f"Unable to prepare launch due to {re}.")
|
||||
raise Exception("request error") from re
|
||||
console.error(f"Unable to prepare launch due to {re}.")
|
||||
raise Exception(str(re)) from re
|
||||
except httpx.HTTPError as he:
|
||||
console.debug(f"Unable to prepare deploy due to {he}.")
|
||||
console.error(f"Unable to prepare deploy due to {he}.")
|
||||
raise Exception(f"{he}") from he
|
||||
except json.JSONDecodeError as jde:
|
||||
console.debug(f"Server did not respond with valid json: {jde}")
|
||||
console.error(f"Server did not respond with valid json: {jde}")
|
||||
raise Exception("internal errors") from jde
|
||||
except (KeyError, ValidationError) as kve:
|
||||
console.debug(f"The server response format is unexpected {kve}")
|
||||
console.error(f"The server response format is unexpected {kve}")
|
||||
raise Exception("internal errors") from kve
|
||||
except ValueError as ve:
|
||||
# This is a recognized client error, currently indicates forbidden
|
||||
raise Exception(f"{ve}") from ve
|
||||
except Exception as ex:
|
||||
console.debug(f"Unexpected error: {ex}.")
|
||||
console.error(f"Unexpected error: {ex}.")
|
||||
raise Exception("internal errors") from ex
|
||||
|
||||
|
||||
@ -460,26 +460,26 @@ def deploy(
|
||||
backend_url=response_json["backend_url"],
|
||||
)
|
||||
except OSError as oe:
|
||||
console.debug(f"Client side error related to file operation: {oe}")
|
||||
console.error(f"Client side error related to file operation: {oe}")
|
||||
raise
|
||||
except httpx.RequestError as re:
|
||||
console.debug(f"Unable to deploy due to request error: {re}")
|
||||
console.error(f"Unable to deploy due to request error: {re}")
|
||||
raise Exception("request error") from re
|
||||
except httpx.HTTPError as he:
|
||||
console.debug(f"Unable to deploy due to {he}.")
|
||||
raise Exception("internal errors") from he
|
||||
console.error(f"Unable to deploy due to {he}.")
|
||||
raise Exception(str) from he
|
||||
except json.JSONDecodeError as jde:
|
||||
console.debug(f"Server did not respond with valid json: {jde}")
|
||||
console.error(f"Server did not respond with valid json: {jde}")
|
||||
raise Exception("internal errors") from jde
|
||||
except (KeyError, ValidationError) as kve:
|
||||
console.debug(f"Post params or server response format unexpected: {kve}")
|
||||
console.error(f"Post params or server response format unexpected: {kve}")
|
||||
raise Exception("internal errors") from kve
|
||||
except AssertionError as ve:
|
||||
console.debug(f"Unable to deploy due to request error: {ve}")
|
||||
console.error(f"Unable to deploy due to request error: {ve}")
|
||||
# re-raise the error back to the user as client side error
|
||||
raise
|
||||
except Exception as ex:
|
||||
console.debug(f"Unable to deploy due to internal errors: {ex}.")
|
||||
console.error(f"Unable to deploy due to internal errors: {ex}.")
|
||||
raise Exception("internal errors") from ex
|
||||
|
||||
|
||||
@ -552,13 +552,13 @@ def list_deployments(
|
||||
for deployment in response.json()
|
||||
]
|
||||
except httpx.RequestError as re:
|
||||
console.debug(f"Unable to list deployments due to request error: {re}")
|
||||
console.error(f"Unable to list deployments due to request error: {re}")
|
||||
raise Exception("request timeout") from re
|
||||
except httpx.HTTPError as he:
|
||||
console.debug(f"Unable to list deployments due to {he}.")
|
||||
console.error(f"Unable to list deployments due to {he}.")
|
||||
raise Exception("internal errors") from he
|
||||
except (ValidationError, KeyError, json.JSONDecodeError) as vkje:
|
||||
console.debug(f"Server response format unexpected: {vkje}")
|
||||
console.error(f"Server response format unexpected: {vkje}")
|
||||
raise Exception("internal errors") from vkje
|
||||
except Exception as ex:
|
||||
console.error(f"Unexpected error: {ex}.")
|
||||
@ -584,15 +584,15 @@ def fetch_token(request_id: str) -> tuple[str, str]:
|
||||
access_token = (resp_json := resp.json()).get("access_token", "")
|
||||
invitation_code = resp_json.get("code", "")
|
||||
except httpx.RequestError as re:
|
||||
console.debug(f"Unable to fetch token due to request error: {re}")
|
||||
console.error(f"Unable to fetch token due to request error: {re}")
|
||||
except httpx.HTTPError as he:
|
||||
console.debug(f"Unable to fetch token due to {he}")
|
||||
console.error(f"Unable to fetch token due to {he}")
|
||||
except json.JSONDecodeError as jde:
|
||||
console.debug(f"Server did not respond with valid json: {jde}")
|
||||
console.error(f"Server did not respond with valid json: {jde}")
|
||||
except KeyError as ke:
|
||||
console.debug(f"Server response format unexpected: {ke}")
|
||||
console.error(f"Server response format unexpected: {ke}")
|
||||
except Exception:
|
||||
console.debug("Unexpected errors: {ex}")
|
||||
console.error("Unexpected errors: {ex}")
|
||||
|
||||
return access_token, invitation_code
|
||||
|
||||
@ -608,7 +608,7 @@ def poll_backend(backend_url: str) -> bool:
|
||||
"""
|
||||
try:
|
||||
console.debug(f"Polling backend at {backend_url}")
|
||||
resp = httpx.get(f"{backend_url}/ping", timeout=HTTP_REQUEST_TIMEOUT)
|
||||
resp = httpx.get(f"{backend_url}/ping", timeout=1)
|
||||
resp.raise_for_status()
|
||||
return True
|
||||
except httpx.HTTPError:
|
||||
@ -626,7 +626,7 @@ def poll_frontend(frontend_url: str) -> bool:
|
||||
"""
|
||||
try:
|
||||
console.debug(f"Polling frontend at {frontend_url}")
|
||||
resp = httpx.get(f"{frontend_url}", timeout=HTTP_REQUEST_TIMEOUT)
|
||||
resp = httpx.get(f"{frontend_url}", timeout=1)
|
||||
resp.raise_for_status()
|
||||
return True
|
||||
except httpx.HTTPError:
|
||||
@ -664,13 +664,13 @@ def delete_deployment(key: str):
|
||||
response.raise_for_status()
|
||||
|
||||
except httpx.TimeoutException as te:
|
||||
console.debug("Unable to delete deployment due to request timeout.")
|
||||
console.error("Unable to delete deployment due to request timeout.")
|
||||
raise Exception("request timeout") from te
|
||||
except httpx.HTTPError as he:
|
||||
console.debug(f"Unable to delete deployment due to {he}.")
|
||||
console.error(f"Unable to delete deployment due to {he}.")
|
||||
raise Exception("internal errors") from he
|
||||
except Exception as ex:
|
||||
console.debug(f"Unexpected errors {ex}.")
|
||||
console.error(f"Unexpected errors {ex}.")
|
||||
raise Exception("internal errors") from ex
|
||||
|
||||
|
||||
@ -755,7 +755,7 @@ def get_deployment_status(key: str) -> DeploymentStatusResponse:
|
||||
),
|
||||
)
|
||||
except Exception as ex:
|
||||
console.debug(f"Unable to get deployment status due to {ex}.")
|
||||
console.error(f"Unable to get deployment status due to {ex}.")
|
||||
raise Exception("internal errors") from ex
|
||||
|
||||
|
||||
@ -772,7 +772,7 @@ def convert_to_local_time(iso_timestamp: str) -> str:
|
||||
local_dt = datetime.fromisoformat(iso_timestamp).astimezone()
|
||||
return local_dt.strftime("%Y-%m-%d %H:%M:%S.%f %Z")
|
||||
except Exception as ex:
|
||||
console.debug(f"Unable to convert iso timestamp {iso_timestamp} due to {ex}.")
|
||||
console.error(f"Unable to convert iso timestamp {iso_timestamp} due to {ex}.")
|
||||
return iso_timestamp
|
||||
|
||||
|
||||
@ -1041,7 +1041,7 @@ def log_out_on_browser():
|
||||
)
|
||||
|
||||
|
||||
async def display_deploy_milestones(key: str, from_iso_timestamp: datetime):
|
||||
async def display_deploy_milestones(key: str, from_iso_timestamp: datetime) -> bool:
|
||||
"""Display the deploy milestone messages reported back from the hosting server.
|
||||
|
||||
Args:
|
||||
@ -1051,6 +1051,9 @@ async def display_deploy_milestones(key: str, from_iso_timestamp: datetime):
|
||||
Raises:
|
||||
ValueError: If a non-empty key is not provided.
|
||||
Exception: If the user is not authenticated.
|
||||
|
||||
Returns:
|
||||
False if server reports back failure, True otherwise.
|
||||
"""
|
||||
if not key:
|
||||
raise ValueError("Non-empty key is required for querying deploy status.")
|
||||
@ -1076,18 +1079,22 @@ async def display_deploy_milestones(key: str, from_iso_timestamp: datetime):
|
||||
]
|
||||
)
|
||||
)
|
||||
if any(
|
||||
msg in row_json["message"].lower()
|
||||
for msg in END_OF_DEPLOYMENT_MESSAGES
|
||||
):
|
||||
server_message = row_json["message"].lower()
|
||||
if "fail" in server_message:
|
||||
console.debug(
|
||||
"Received failure message, stop event message streaming"
|
||||
)
|
||||
return False
|
||||
if any(msg in server_message for msg in END_OF_DEPLOYMENT_MESSAGES):
|
||||
console.debug(
|
||||
"Received end of deployment message, stop event message streaming"
|
||||
)
|
||||
return
|
||||
return True
|
||||
else:
|
||||
console.debug("Server responded, no new events yet, this is normal")
|
||||
except Exception as ex:
|
||||
console.debug(f"Unable to get more deployment events due to {ex}.")
|
||||
return False
|
||||
|
||||
|
||||
def wait_for_server_to_pick_up_request():
|
||||
@ -1141,16 +1148,16 @@ def get_regions() -> list[dict]:
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
if response_json is None or not isinstance(response_json, list):
|
||||
console.debug("Expect server to return a list ")
|
||||
console.error("Expect server to return a list ")
|
||||
return []
|
||||
if (
|
||||
response_json
|
||||
and response_json[0] is not None
|
||||
and not isinstance(response_json[0], dict)
|
||||
):
|
||||
console.debug("Expect return values are dict's")
|
||||
console.error("Expect return values are dict's")
|
||||
return []
|
||||
return response_json
|
||||
except Exception as ex:
|
||||
console.debug(f"Unable to get regions due to {ex}.")
|
||||
console.error(f"Unable to get regions due to {ex}.")
|
||||
return []
|
||||
|
Loading…
Reference in New Issue
Block a user