diff --git a/python/graphscope/gsctl/commands/interactive/glob.py b/python/graphscope/gsctl/commands/interactive/glob.py index 4167d7277188..ed1847ecee43 100644 --- a/python/graphscope/gsctl/commands/interactive/glob.py +++ b/python/graphscope/gsctl/commands/interactive/glob.py @@ -19,18 +19,22 @@ import click import yaml +from graphscope.gsctl.impl import bind_datasource_in_batch from graphscope.gsctl.impl import create_graph from graphscope.gsctl.impl import delete_graph_by_id +from graphscope.gsctl.impl import delete_job_by_id from graphscope.gsctl.impl import get_datasource_by_id from graphscope.gsctl.impl import get_graph_id_by_name +from graphscope.gsctl.impl import get_job_by_id from graphscope.gsctl.impl import list_graphs from graphscope.gsctl.impl import list_jobs from graphscope.gsctl.impl import list_service_status from graphscope.gsctl.impl import list_stored_procedures -from graphscope.gsctl.impl import restart_service from graphscope.gsctl.impl import start_service -from graphscope.gsctl.impl import stop_service +from graphscope.gsctl.impl import submit_dataloading_job from graphscope.gsctl.impl import switch_context +from graphscope.gsctl.impl import unbind_edge_datasource +from graphscope.gsctl.impl import unbind_vertex_datasource from graphscope.gsctl.utils import TreeDisplay from graphscope.gsctl.utils import err from graphscope.gsctl.utils import info @@ -47,19 +51,19 @@ def cli(): @cli.group() def create(): - """Create a new graph in database""" + """Create graph, data source, loader job from file""" pass @cli.group() def delete(): - """Delete a graph by identifier""" + """Delete graph, data source, loader job by id""" pass @cli.group() -def service(): - """Start, stop, and restart the database service""" +def desc(): + """Show job's details by id""" pass @@ -71,7 +75,13 @@ def service(): def use(context, graph_identifier): """Switch to GRAPH context, see identifier with `ls` command""" try: - switch_context(get_graph_id_by_name(graph_identifier)) + graph_identifier = get_graph_id_by_name(graph_identifier) + status = list_service_status() + for s in status: + if s.graph_id == graph_identifier and s.status != "Running": + info(f"Starting service on graph {graph_identifier}...") + start_service(graph_identifier) + switch_context(graph_identifier) except Exception as e: err(f"Failed to switch context: {str(e)}") else: @@ -89,7 +99,7 @@ def ls(l): # noqa: F811, E741 # schema tree.create_graph_node(g, recursive=l) if l: - # data source mappin + # data source mapping datasource_mapping = get_datasource_by_id(g.id) tree.create_datasource_mapping_node(g, datasource_mapping) # stored procedure @@ -139,79 +149,127 @@ def graph(graph_identifier): # noqa: F811 succ(f"Delete graph {graph_identifier} successfully.") -@service.command -def stop(): # noqa: F811 - """Stop current database service""" +@create.command +@click.option( + "-g", + "--graph_identifier", + required=True, + help="See graph identifier with `ls` command", +) +@click.option( + "-f", + "--filename", + required=True, + help="Path of yaml file", +) +def datasource(graph_identifier, filename): # noqa: F811 + """Bind data source mapping from file""" + if not is_valid_file_path(filename): + err(f"Invalid file: {filename}") + return + graph_identifier = get_graph_id_by_name(graph_identifier) + try: + datasource = read_yaml_file(filename) + bind_datasource_in_batch(graph_identifier, datasource) + except Exception as e: + err(f"Failed to bind data source: {str(e)}") + else: + succ("Bind data source successfully.") + + +@delete.command +@click.option( + "-g", + "--graph_identifier", + required=True, + help="See graph identifier with `ls` command", +) +@click.option( + "-t", + "--type", + required=True, + help="Vertex or edge type", +) +@click.option( + "-s", + "--source_vertex_type", + required=False, + help="Source vertex type of the edge [edge only]", +) +@click.option( + "-d", + "--destination_vertex_type", + required=False, + help="Destination vertex type of the edge [edge only]", +) +def datasource( # noqa: F811 + graph_identifier, type, source_vertex_type, destination_vertex_type +): + """Unbind data source mapping on vertex or edge type""" try: - stop_service() + graph_identifier = get_graph_id_by_name(graph_identifier) + if source_vertex_type is not None and destination_vertex_type is not None: + unbind_edge_datasource( + graph_identifier, type, source_vertex_type, destination_vertex_type + ) + else: + unbind_vertex_datasource(graph_identifier, type) except Exception as e: - err(f"Failed to stop service: {str(e)}") + err(f"Failed to unbind data source: {str(e)}") else: - succ("Service stopped.") + succ("Unbind data source successfully.") -@service.command +@create.command() @click.option( "-g", "--graph_identifier", required=True, help="See graph identifier with `ls` command", ) -def start(graph_identifier): # noqa: F811 - """Start database service on a certain graph""" +@click.option( + "-f", + "--filename", + required=True, + help="Path of yaml file", +) +def loaderjob(graph_identifier, filename): # noqa: F811 + """Create a data loading job from file""" + if not is_valid_file_path(filename): + err(f"Invalid file: {filename}") + return + graph_identifier = get_graph_id_by_name(graph_identifier) try: - start_service(get_graph_id_by_name(graph_identifier)) + config = read_yaml_file(filename) + jobid = submit_dataloading_job(graph_identifier, config) except Exception as e: - err(f"Failed to start service on graph {graph_identifier}: {str(e)}") + err(f"Failed to create a job: {str(e)}") else: - succ(f"Start service on graph {graph_identifier} successfully") + succ(f"Create job {jobid} successfully.") -@service.command -def restart(): # noqa: F811 - """Restart database service on current graph""" +@delete.command() +@click.argument("identifier", required=True) +def job(identifier): # noqa: F811 + """Cancel a job, see identifier with `ls` command""" try: - restart_service() + delete_job_by_id(identifier) except Exception as e: - err(f"Failed to restart service: {str(e)}") + err(f"Failed to delete job {identifier}: {str(e)}") else: - succ("Service restarted.") - - -@service.command -def ls(): # noqa: F811 - """Display current service status""" - - def _construct_and_display_data(status): - head = [ - "STATUS", - "SERVING_GRAPH(IDENTIFIER)", - "CYPHER_ENDPOINT", - "HQPS_ENDPOINT", - "GREMLIN_ENDPOINT", - ] - data = [head] - for s in status: - if s.status == "Stopped": - data.append([s.status, s.graph_id, "-", "-", "-"]) - else: - data.append( - [ - s.status, - s.graph_id, - s.sdk_endpoints.cypher, - s.sdk_endpoints.hqps, - s.sdk_endpoints.gremlin, - ] - ) - terminal_display(data) + succ(f"Delete job {identifier} successfully.") + +@desc.command() +@click.argument("identifier", required=True) +def job(identifier): # noqa: F811 + """Show details of job, see identifier with `ls` command""" try: - status = list_service_status() + job = get_job_by_id(identifier) except Exception as e: - err(f"Failed to list service status: {str(e)}") + err(f"Failed to get job: {str(e)}") else: - _construct_and_display_data(status) + info(yaml.dump(job.to_dict())) if __name__ == "__main__": diff --git a/python/graphscope/gsctl/commands/interactive/graph.py b/python/graphscope/gsctl/commands/interactive/graph.py index 942972f3db1e..640ff5a12d6f 100644 --- a/python/graphscope/gsctl/commands/interactive/graph.py +++ b/python/graphscope/gsctl/commands/interactive/graph.py @@ -20,26 +20,22 @@ import yaml from graphscope.gsctl.config import get_current_context -from graphscope.gsctl.impl import bind_datasource_in_batch from graphscope.gsctl.impl import create_stored_procedure -from graphscope.gsctl.impl import delete_job_by_id from graphscope.gsctl.impl import delete_stored_procedure_by_id from graphscope.gsctl.impl import get_datasource_by_id -from graphscope.gsctl.impl import get_graph_id_by_name -from graphscope.gsctl.impl import get_job_by_id from graphscope.gsctl.impl import list_graphs -from graphscope.gsctl.impl import list_jobs +from graphscope.gsctl.impl import list_service_status from graphscope.gsctl.impl import list_stored_procedures -from graphscope.gsctl.impl import submit_dataloading_job +from graphscope.gsctl.impl import start_service +from graphscope.gsctl.impl import stop_service from graphscope.gsctl.impl import switch_context -from graphscope.gsctl.impl import unbind_edge_datasource -from graphscope.gsctl.impl import unbind_vertex_datasource from graphscope.gsctl.utils import TreeDisplay from graphscope.gsctl.utils import err from graphscope.gsctl.utils import info from graphscope.gsctl.utils import is_valid_file_path from graphscope.gsctl.utils import read_yaml_file from graphscope.gsctl.utils import succ +from graphscope.gsctl.utils import terminal_display @click.group() @@ -49,19 +45,25 @@ def cli(): @cli.group() def create(): - """Create stored procedure, data source, loader job from file""" + """Create stored procedure from file""" pass @cli.group() def delete(): - """Delete stored procedure, data source, loader job by id""" + """Delete stored procedure by id""" pass @cli.group() def desc(): - """Show details of job status and stored procedure by id""" + """Show stored procedure's details by id""" + pass + + +@cli.group() +def service(): + """Start, stop, and restart the database service""" pass @@ -73,7 +75,7 @@ def use(): @cli.command() def ls(): # noqa: F811 - """Display schema, stored procedure, and job information""" + """Display schema and stored procedure information""" tree = TreeDisplay() # context current_context = get_current_context() @@ -92,9 +94,6 @@ def ls(): # noqa: F811 # stored procedure stored_procedures = list_stored_procedures(using_graph.id) tree.create_stored_procedure_node(using_graph, stored_procedures) - # job - jobs = list_jobs() - tree.create_job_node(using_graph, jobs) except Exception as e: err(f"Failed to display graph information: {str(e)}") else: @@ -138,112 +137,6 @@ def storedproc(identifier): # noqa: F811 succ(f"Delete stored procedure {identifier} successfully.") -@create.command -@click.option( - "-f", - "--filename", - required=True, - help="Path of yaml file", -) -def datasource(filename): # noqa: F811 - """Bind data source mapping from file""" - if not is_valid_file_path(filename): - err(f"Invalid file: {filename}") - return - current_context = get_current_context() - graph_identifier = current_context.context - try: - datasource = read_yaml_file(filename) - bind_datasource_in_batch(graph_identifier, datasource) - except Exception as e: - err(f"Failed to bind data source: {str(e)}") - else: - succ("Bind data source successfully.") - - -@delete.command -@click.option( - "-t", - "--type", - required=True, - help="Vertex or edge type", -) -@click.option( - "-s", - "--source_vertex_type", - required=False, - help="Source vertex type of the edge [edge only]", -) -@click.option( - "-d", - "--destination_vertex_type", - required=False, - help="Destination vertex type of the edge [edge only]", -) -def datasource(type, source_vertex_type, destination_vertex_type): # noqa: F811 - """Unbind data source mapping on vertex or edge type""" - try: - current_context = get_current_context() - graph_identifier = current_context.context - if source_vertex_type is not None and destination_vertex_type is not None: - unbind_edge_datasource( - graph_identifier, type, source_vertex_type, destination_vertex_type - ) - else: - unbind_vertex_datasource(graph_identifier, type) - except Exception as e: - err(f"Failed to unbind data source: {str(e)}") - else: - succ("Unbind data source successfully.") - - -@create.command() -@click.option( - "-f", - "--filename", - required=True, - help="Path of yaml file", -) -def loaderjob(filename): # noqa: F811 - """Create a data loading job from file""" - if not is_valid_file_path(filename): - err(f"Invalid file: {filename}") - return - current_context = get_current_context() - graph_identifier = current_context.context - try: - config = read_yaml_file(filename) - jobid = submit_dataloading_job(graph_identifier, config) - except Exception as e: - err(f"Failed to create a job: {str(e)}") - else: - succ(f"Create job {jobid} successfully.") - - -@delete.command() -@click.argument("identifier", required=True) -def job(identifier): # noqa: F811 - """Cancel a job, see identifier with `ls` command""" - try: - delete_job_by_id(identifier) - except Exception as e: - err(f"Failed to delete job {identifier}: {str(e)}") - else: - succ(f"Delete job {identifier} successfully.") - - -@desc.command() -@click.argument("identifier", required=True) -def job(identifier): # noqa: F811 - """Show details of job, see identifier with `ls` command""" - try: - job = get_job_by_id(identifier) - except Exception as e: - err(f"Failed to get job: {str(e)}") - else: - info(yaml.dump(job.to_dict())) - - @desc.command() @click.argument("identifier", required=True) def storedproc(identifier): # noqa: F811 @@ -268,6 +161,77 @@ def storedproc(identifier): # noqa: F811 err(f"Stored Procedure {identifier} not found on {graph_id}.") +@service.command +def stop(): # noqa: F811 + """Stop current database service""" + try: + stop_service() + except Exception as e: + err(f"Failed to stop service: {str(e)}") + else: + succ("Service stopped.") + + +@service.command +def start(): # noqa: F811 + """Start current database service""" + try: + current_context = get_current_context() + graph_identifier = current_context.context + + status = list_service_status() + for s in status: + if s.graph_id == graph_identifier: + if s.status != "Running": + info(f"Starting service on graph {graph_identifier}...") + start_service(graph_identifier) + succ("Service restarted.") + else: + info("Service is running...") + except Exception as e: + err(f"Failed to start service: {str(e)}") + + +@service.command +def status(): # noqa: F811 + """Display current service status""" + + def _construct_and_display_data(status): + current_context = get_current_context() + graph_identifier = current_context.context + + head = [ + "STATUS", + "SERVING_GRAPH(IDENTIFIER)", + "CYPHER_ENDPOINT", + "HQPS_ENDPOINT", + "GREMLIN_ENDPOINT", + ] + data = [head] + for s in status: + if s.graph_id == graph_identifier: + if s.status == "Stopped": + data.append([s.status, s.graph_id, "-", "-", "-"]) + else: + data.append( + [ + s.status, + s.graph_id, + s.sdk_endpoints.cypher, + s.sdk_endpoints.hqps, + s.sdk_endpoints.gremlin, + ] + ) + terminal_display(data) + + try: + status = list_service_status() + except Exception as e: + err(f"Failed to list service status: {str(e)}") + else: + _construct_and_display_data(status) + + @use.command(name="GLOBAL") def _global(): """Switch back to the global scope""" diff --git a/python/graphscope/gsctl/utils.py b/python/graphscope/gsctl/utils.py index 167cbe20839a..f5fb39b894cb 100644 --- a/python/graphscope/gsctl/utils.py +++ b/python/graphscope/gsctl/utils.py @@ -483,7 +483,5 @@ def show(self, graph_identifier=None, stdout=False, sorting=False): f"{graph_identifier}_stored_procedure" ) click.secho(stored_procedure_tree.show(stdout=False, sorting=False)) - job_tree = self.tree.subtree(f"{graph_identifier}_job") - click.secho(job_tree.show(stdout=False, sorting=False)) else: click.secho(self.tree.show(stdout=stdout, sorting=sorting))