gsctl 0.29.0a20250114__py2.py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- graphscope/flex/rest/__init__.py +106 -0
- graphscope/flex/rest/api/__init__.py +12 -0
- graphscope/flex/rest/api/alert_api.py +2790 -0
- graphscope/flex/rest/api/data_source_api.py +1177 -0
- graphscope/flex/rest/api/deployment_api.py +1323 -0
- graphscope/flex/rest/api/graph_api.py +2813 -0
- graphscope/flex/rest/api/job_api.py +1408 -0
- graphscope/flex/rest/api/service_api.py +1316 -0
- graphscope/flex/rest/api/stored_procedure_api.py +1454 -0
- graphscope/flex/rest/api/utils_api.py +310 -0
- graphscope/flex/rest/api_client.py +789 -0
- graphscope/flex/rest/api_response.py +21 -0
- graphscope/flex/rest/configuration.py +451 -0
- graphscope/flex/rest/exceptions.py +200 -0
- graphscope/flex/rest/models/__init__.py +82 -0
- graphscope/flex/rest/models/base_edge_type.py +102 -0
- graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner.py +108 -0
- graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner_x_csr_params.py +98 -0
- graphscope/flex/rest/models/base_property_meta.py +105 -0
- graphscope/flex/rest/models/base_vertex_type.py +96 -0
- graphscope/flex/rest/models/base_vertex_type_x_csr_params.py +88 -0
- graphscope/flex/rest/models/column_mapping.py +94 -0
- graphscope/flex/rest/models/column_mapping_column.py +90 -0
- graphscope/flex/rest/models/create_alert_receiver_request.py +103 -0
- graphscope/flex/rest/models/create_alert_rule_request.py +112 -0
- graphscope/flex/rest/models/create_dataloading_job_response.py +88 -0
- graphscope/flex/rest/models/create_edge_type.py +114 -0
- graphscope/flex/rest/models/create_graph_request.py +106 -0
- graphscope/flex/rest/models/create_graph_response.py +88 -0
- graphscope/flex/rest/models/create_graph_schema_request.py +106 -0
- graphscope/flex/rest/models/create_property_meta.py +105 -0
- graphscope/flex/rest/models/create_stored_proc_request.py +101 -0
- graphscope/flex/rest/models/create_stored_proc_response.py +88 -0
- graphscope/flex/rest/models/create_vertex_type.py +108 -0
- graphscope/flex/rest/models/dataloading_job_config.py +136 -0
- graphscope/flex/rest/models/dataloading_job_config_edges_inner.py +92 -0
- graphscope/flex/rest/models/dataloading_job_config_loading_config.py +104 -0
- graphscope/flex/rest/models/dataloading_job_config_loading_config_format.py +90 -0
- graphscope/flex/rest/models/dataloading_job_config_vertices_inner.py +88 -0
- graphscope/flex/rest/models/dataloading_mr_job_config.py +88 -0
- graphscope/flex/rest/models/date_type.py +88 -0
- graphscope/flex/rest/models/edge_mapping.py +122 -0
- graphscope/flex/rest/models/edge_mapping_type_triplet.py +92 -0
- graphscope/flex/rest/models/error.py +90 -0
- graphscope/flex/rest/models/get_alert_message_response.py +123 -0
- graphscope/flex/rest/models/get_alert_receiver_response.py +107 -0
- graphscope/flex/rest/models/get_alert_rule_response.py +114 -0
- graphscope/flex/rest/models/get_edge_type.py +116 -0
- graphscope/flex/rest/models/get_graph_response.py +139 -0
- graphscope/flex/rest/models/get_graph_schema_response.py +106 -0
- graphscope/flex/rest/models/get_pod_log_response.py +88 -0
- graphscope/flex/rest/models/get_property_meta.py +107 -0
- graphscope/flex/rest/models/get_resource_usage_response.py +105 -0
- graphscope/flex/rest/models/get_storage_usage_response.py +88 -0
- graphscope/flex/rest/models/get_stored_proc_response.py +130 -0
- graphscope/flex/rest/models/get_vertex_type.py +110 -0
- graphscope/flex/rest/models/gs_data_type.py +152 -0
- graphscope/flex/rest/models/job_status.py +107 -0
- graphscope/flex/rest/models/long_text.py +93 -0
- graphscope/flex/rest/models/node_status.py +94 -0
- graphscope/flex/rest/models/parameter.py +96 -0
- graphscope/flex/rest/models/pod_status.py +108 -0
- graphscope/flex/rest/models/primitive_type.py +95 -0
- graphscope/flex/rest/models/resource_usage.py +92 -0
- graphscope/flex/rest/models/running_deployment_info.py +128 -0
- graphscope/flex/rest/models/running_deployment_status.py +124 -0
- graphscope/flex/rest/models/schema_mapping.py +106 -0
- graphscope/flex/rest/models/service_status.py +112 -0
- graphscope/flex/rest/models/service_status_sdk_endpoints.py +94 -0
- graphscope/flex/rest/models/start_service_request.py +88 -0
- graphscope/flex/rest/models/stored_procedure_meta.py +126 -0
- graphscope/flex/rest/models/string_type.py +92 -0
- graphscope/flex/rest/models/string_type_string.py +124 -0
- graphscope/flex/rest/models/temporal_type.py +92 -0
- graphscope/flex/rest/models/temporal_type_temporal.py +138 -0
- graphscope/flex/rest/models/time_stamp_type.py +88 -0
- graphscope/flex/rest/models/update_alert_message_status_request.py +97 -0
- graphscope/flex/rest/models/update_stored_proc_request.py +88 -0
- graphscope/flex/rest/models/upload_file_response.py +90 -0
- graphscope/flex/rest/models/vertex_mapping.py +100 -0
- graphscope/flex/rest/py.typed +0 -0
- graphscope/flex/rest/rest.py +258 -0
- graphscope/gsctl/V6D_VERSION +1 -0
- graphscope/gsctl/VERSION +1 -0
- graphscope/gsctl/__init__.py +22 -0
- graphscope/gsctl/commands/__init__.py +148 -0
- graphscope/gsctl/commands/common.py +200 -0
- graphscope/gsctl/commands/dev.py +448 -0
- graphscope/gsctl/commands/insight/__init__.py +17 -0
- graphscope/gsctl/commands/insight/glob.py +234 -0
- graphscope/gsctl/commands/insight/graph.py +205 -0
- graphscope/gsctl/commands/interactive/__init__.py +17 -0
- graphscope/gsctl/commands/interactive/glob.py +280 -0
- graphscope/gsctl/commands/interactive/graph.py +259 -0
- graphscope/gsctl/config.py +221 -0
- graphscope/gsctl/gsctl.py +51 -0
- graphscope/gsctl/impl/__init__.py +64 -0
- graphscope/gsctl/impl/alert.py +135 -0
- graphscope/gsctl/impl/common.py +53 -0
- graphscope/gsctl/impl/datasource.py +80 -0
- graphscope/gsctl/impl/deployment.py +62 -0
- graphscope/gsctl/impl/graph.py +150 -0
- graphscope/gsctl/impl/job.py +63 -0
- graphscope/gsctl/impl/service.py +62 -0
- graphscope/gsctl/impl/stored_procedure.py +92 -0
- graphscope/gsctl/impl/utils.py +38 -0
- graphscope/gsctl/scripts/install_deps.sh +969 -0
- graphscope/gsctl/tests/__init__.py +17 -0
- graphscope/gsctl/tests/test_graphscope_insight.py +401 -0
- graphscope/gsctl/tests/test_interactive.py +516 -0
- graphscope/gsctl/utils.py +337 -0
- graphscope/gsctl/version.py +31 -0
- gsctl-0.29.0a20250114.dist-info/METADATA +20 -0
- gsctl-0.29.0a20250114.dist-info/RECORD +117 -0
- gsctl-0.29.0a20250114.dist-info/WHEEL +6 -0
- gsctl-0.29.0a20250114.dist-info/entry_points.txt +3 -0
- gsctl-0.29.0a20250114.dist-info/top_level.txt +1 -0
@@ -0,0 +1,448 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright 2023 Alibaba Group Holding Limited. All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
"""Group of commands for GraphScope development"""
|
20
|
+
|
21
|
+
import io
|
22
|
+
import os
|
23
|
+
import subprocess
|
24
|
+
import sys
|
25
|
+
|
26
|
+
import click
|
27
|
+
|
28
|
+
# Make sure this file doesn't depend on any graphscope directories for
|
29
|
+
# installing dependencies, so we can't `import graphscope` here.
|
30
|
+
version_file_path = os.path.join(
|
31
|
+
os.path.dirname(os.path.abspath(__file__)), "..", "VERSION"
|
32
|
+
)
|
33
|
+
with open(version_file_path, "r", encoding="utf-8") as fp:
|
34
|
+
__version__ = fp.read().strip()
|
35
|
+
|
36
|
+
v6d_version_file_path = os.path.join(
|
37
|
+
os.path.dirname(os.path.abspath(__file__)), "..", "V6D_VERSION"
|
38
|
+
)
|
39
|
+
with open(v6d_version_file_path, "r", encoding="utf-8") as fp:
|
40
|
+
__v6d_version__ = fp.read().strip()
|
41
|
+
|
42
|
+
# Interactive docker container config
|
43
|
+
INTERACTIVE_DOCKER_CONTAINER_NAME = "gs-interactive-instance"
|
44
|
+
INTERACTIVE_DOCKER_CONTAINER_LABEL = "flex=interactive"
|
45
|
+
INTERACTIVE_DOCKER_DEFAULT_CONFIG_PATH = "/opt/flex/share/interactive_config.yaml"
|
46
|
+
|
47
|
+
scripts_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "scripts")
|
48
|
+
install_deps_script = os.path.join(scripts_dir, "install_deps.sh")
|
49
|
+
default_graphscope_repo_path = os.path.join(
|
50
|
+
os.path.dirname(os.path.realpath(__file__)),
|
51
|
+
"..",
|
52
|
+
"..",
|
53
|
+
"..",
|
54
|
+
"..",
|
55
|
+
)
|
56
|
+
|
57
|
+
|
58
|
+
def run_shell_cmd(cmd, workingdir):
|
59
|
+
"""wrapper function to run a shell command/scripts."""
|
60
|
+
click.secho(f"run a shell command on cwd={workingdir}. \ncmd=\"{' '.join(cmd)}\"")
|
61
|
+
proc = subprocess.Popen(
|
62
|
+
cmd,
|
63
|
+
cwd=workingdir,
|
64
|
+
env=os.environ.copy(),
|
65
|
+
stdout=subprocess.PIPE,
|
66
|
+
stderr=subprocess.STDOUT,
|
67
|
+
)
|
68
|
+
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
69
|
+
click.secho(line.rstrip())
|
70
|
+
proc.wait()
|
71
|
+
return proc.returncode
|
72
|
+
|
73
|
+
|
74
|
+
@click.group()
|
75
|
+
def cli():
|
76
|
+
# nothing happens
|
77
|
+
pass
|
78
|
+
|
79
|
+
|
80
|
+
@cli.group()
|
81
|
+
def flexbuild():
|
82
|
+
"""Build docker image for Interactive, Insight product."""
|
83
|
+
pass
|
84
|
+
|
85
|
+
|
86
|
+
@cli.group()
|
87
|
+
def instance():
|
88
|
+
"""Deploy, destroy a Flex instance.
|
89
|
+
|
90
|
+
The `instance` subcommand is responsible for managing the Flex Instances.
|
91
|
+
"""
|
92
|
+
pass
|
93
|
+
|
94
|
+
|
95
|
+
@flexbuild.command()
|
96
|
+
@click.option(
|
97
|
+
"--app",
|
98
|
+
type=click.Choice(["docker"]),
|
99
|
+
required=True,
|
100
|
+
help="Application type of the built artifacts you want to build",
|
101
|
+
)
|
102
|
+
@click.option(
|
103
|
+
"--graphscope-repo",
|
104
|
+
required=False,
|
105
|
+
help="GraphScope code repo location.",
|
106
|
+
)
|
107
|
+
def insight(app, graphscope_repo):
|
108
|
+
"""Build GraphScope Insight for BI analysis scenarios"""
|
109
|
+
if graphscope_repo is None:
|
110
|
+
graphscope_repo = default_graphscope_repo_path
|
111
|
+
insight_build_dir = os.path.join(graphscope_repo, "k8s")
|
112
|
+
if not os.path.exists(insight_build_dir) or not os.path.isdir(insight_build_dir):
|
113
|
+
click.secho(
|
114
|
+
f"No such file or directory {insight_build_dir}, try --graphscope-repo param.",
|
115
|
+
fg="red",
|
116
|
+
)
|
117
|
+
return
|
118
|
+
cmd = ["make", "graphscope-store", "ENABLE_COORDINATOR=true"]
|
119
|
+
sys.exit(run_shell_cmd(cmd, os.path.join(graphscope_repo, insight_build_dir)))
|
120
|
+
|
121
|
+
|
122
|
+
@flexbuild.command()
|
123
|
+
@click.option(
|
124
|
+
"--app",
|
125
|
+
type=click.Choice(["docker"]),
|
126
|
+
required=True,
|
127
|
+
help="Application type of the built artifacts you want to build",
|
128
|
+
)
|
129
|
+
@click.option(
|
130
|
+
"--graphscope-repo",
|
131
|
+
required=False,
|
132
|
+
help="GraphScope code repo location.",
|
133
|
+
)
|
134
|
+
def interactive(app, graphscope_repo):
|
135
|
+
"""Build Interactive for high throughput scenarios"""
|
136
|
+
if graphscope_repo is None:
|
137
|
+
graphscope_repo = default_graphscope_repo_path
|
138
|
+
interactive_build_dir = os.path.join(graphscope_repo, "k8s")
|
139
|
+
if not os.path.exists(interactive_build_dir) or not os.path.isdir(
|
140
|
+
interactive_build_dir
|
141
|
+
):
|
142
|
+
click.secho("[FAILED] ", nl=False, fg="red", bold=True)
|
143
|
+
click.secho(
|
144
|
+
f"No such file or directory {interactive_build_dir}, try --graphscope-repo param.",
|
145
|
+
)
|
146
|
+
return
|
147
|
+
cmd = ["make", "flex-interactive", "ENABLE_COORDINATOR=true"]
|
148
|
+
sys.exit(run_shell_cmd(cmd, os.path.join(graphscope_repo, interactive_build_dir)))
|
149
|
+
|
150
|
+
|
151
|
+
@instance.command
|
152
|
+
@click.option(
|
153
|
+
"--type",
|
154
|
+
type=click.Choice(["interactive"], case_sensitive=False),
|
155
|
+
help="Instance type, e.g. Interactive",
|
156
|
+
required=True,
|
157
|
+
)
|
158
|
+
@click.option(
|
159
|
+
"--coordinator-port",
|
160
|
+
help="Mapping port of Coordinator [docker only]",
|
161
|
+
default=8080,
|
162
|
+
show_default=True,
|
163
|
+
required=False,
|
164
|
+
)
|
165
|
+
@click.option(
|
166
|
+
"--admin-port",
|
167
|
+
help="Mapping port of Interactive Admin service [docker only]",
|
168
|
+
default=7777,
|
169
|
+
show_default=True,
|
170
|
+
required=False,
|
171
|
+
)
|
172
|
+
@click.option(
|
173
|
+
"--storedproc-port",
|
174
|
+
help="Mapping port of stored procedure query [docker only]",
|
175
|
+
default=10000,
|
176
|
+
show_default=True,
|
177
|
+
required=False,
|
178
|
+
)
|
179
|
+
@click.option(
|
180
|
+
"--cypher-port",
|
181
|
+
help="Mapping port of cypher query [docker only]",
|
182
|
+
default=7687,
|
183
|
+
show_default=True,
|
184
|
+
required=False,
|
185
|
+
)
|
186
|
+
@click.option(
|
187
|
+
"--interactive-config",
|
188
|
+
help="Interactive config file path [docker only]",
|
189
|
+
required=False,
|
190
|
+
default=None,
|
191
|
+
)
|
192
|
+
@click.option(
|
193
|
+
"--gremlin-port",
|
194
|
+
help="Mapping port of gremlin query, -1 means disable mapping [docker only]",
|
195
|
+
default=-1,
|
196
|
+
show_default=True,
|
197
|
+
required=False,
|
198
|
+
)
|
199
|
+
@click.option(
|
200
|
+
"--container-name",
|
201
|
+
help="Docker container name [docker only]",
|
202
|
+
default=INTERACTIVE_DOCKER_CONTAINER_NAME,
|
203
|
+
show_default=True,
|
204
|
+
required=False,
|
205
|
+
)
|
206
|
+
@click.option(
|
207
|
+
"--image-registry",
|
208
|
+
help="Docker image registry used to launch instance",
|
209
|
+
default="registry.cn-hongkong.aliyuncs.com/graphscope",
|
210
|
+
show_default=True,
|
211
|
+
required=False,
|
212
|
+
)
|
213
|
+
@click.option(
|
214
|
+
"--image-tag",
|
215
|
+
help="Docker image tag used to launch instance",
|
216
|
+
default=__version__,
|
217
|
+
show_default=True,
|
218
|
+
required=False,
|
219
|
+
)
|
220
|
+
def deploy(
|
221
|
+
type,
|
222
|
+
container_name,
|
223
|
+
image_registry,
|
224
|
+
image_tag,
|
225
|
+
coordinator_port,
|
226
|
+
admin_port,
|
227
|
+
storedproc_port,
|
228
|
+
cypher_port,
|
229
|
+
gremlin_port,
|
230
|
+
interactive_config,
|
231
|
+
): # noqa: F811
|
232
|
+
"""Deploy a GraphScope Flex instance"""
|
233
|
+
cmd = []
|
234
|
+
if type == "interactive":
|
235
|
+
cmd = [
|
236
|
+
"docker",
|
237
|
+
"run",
|
238
|
+
"-d",
|
239
|
+
"--name",
|
240
|
+
container_name,
|
241
|
+
"--label",
|
242
|
+
INTERACTIVE_DOCKER_CONTAINER_LABEL,
|
243
|
+
"-p",
|
244
|
+
f"{coordinator_port}:8080",
|
245
|
+
"-p",
|
246
|
+
f"{admin_port}:7777",
|
247
|
+
"-p",
|
248
|
+
f"{storedproc_port}:10000",
|
249
|
+
"-p",
|
250
|
+
f"{cypher_port}:7687",
|
251
|
+
]
|
252
|
+
if gremlin_port != -1:
|
253
|
+
cmd.extend(["-p", f"{gremlin_port}:8182"])
|
254
|
+
if interactive_config is not None:
|
255
|
+
if not os.path.isfile(interactive_config):
|
256
|
+
click.secho(
|
257
|
+
f"Interactive config file {interactive_config} does not exist.",
|
258
|
+
fg="red",
|
259
|
+
)
|
260
|
+
return
|
261
|
+
interactive_config = os.path.abspath(interactive_config)
|
262
|
+
cmd.extend(
|
263
|
+
["-v", f"{interactive_config}:{INTERACTIVE_DOCKER_DEFAULT_CONFIG_PATH}"]
|
264
|
+
)
|
265
|
+
image = f"{image_registry}/{type}:{image_tag}"
|
266
|
+
cmd.extend([image, "--enable-coordinator"])
|
267
|
+
cmd.extend(
|
268
|
+
[
|
269
|
+
"--port-mapping",
|
270
|
+
f"8080:{coordinator_port},7777:{admin_port},10000:{storedproc_port},7687:{cypher_port}",
|
271
|
+
]
|
272
|
+
)
|
273
|
+
returncode = run_shell_cmd(cmd, os.getcwd())
|
274
|
+
if returncode == 0:
|
275
|
+
message = f"""
|
276
|
+
Coordinator is listening on {coordinator_port} port, you can connect to coordinator by:
|
277
|
+
gsctl connect --coordinator-endpoint http://127.0.0.1:{coordinator_port}
|
278
|
+
|
279
|
+
Interactive service is ready, you can connect to the interactive service with interactive sdk:
|
280
|
+
Interactive Admin service is listening at
|
281
|
+
http://127.0.0.1:{admin_port},
|
282
|
+
You can connect to admin service with Interactive SDK, with following environment variables declared.
|
283
|
+
|
284
|
+
############################################################################################
|
285
|
+
export INTERACTIVE_ADMIN_ENDPOINT=http://127.0.0.1:{admin_port}
|
286
|
+
export INTERACTIVE_STORED_PROC_ENDPOINT=http://127.0.0.1:{storedproc_port}
|
287
|
+
export INTERACTIVE_CYPHER_ENDPOINT=neo4j://127.0.0.1:{cypher_port}
|
288
|
+
"""
|
289
|
+
if gremlin_port != -1:
|
290
|
+
message += f"""
|
291
|
+
export INTERACTIVE_GREMLIN_ENDPOINT=ws://127.0.0.1:{gremlin_port}/gremlin
|
292
|
+
"""
|
293
|
+
message += """
|
294
|
+
############################################################################################
|
295
|
+
|
296
|
+
See https://graphscope.io/docs/latest/flex/interactive/development/java/java_sdk and
|
297
|
+
https://graphscope.io/docs/latest/flex/interactive/development/python/python_sdk for more details
|
298
|
+
about the usage of Interactive SDK.
|
299
|
+
|
300
|
+
Apart from interactive sdk, you can also use neo4j native tools(like cypher-shell) to connect to cypher endpoint,
|
301
|
+
and gremlin console to connect to gremlin endpoint.
|
302
|
+
"""
|
303
|
+
click.secho("[SUCCESS] ", nl=False, fg="green", bold=True)
|
304
|
+
click.secho(message, bold=False, fg="blue")
|
305
|
+
|
306
|
+
|
307
|
+
@instance.command
|
308
|
+
@click.option(
|
309
|
+
"--type",
|
310
|
+
type=click.Choice(["interactive"], case_sensitive=False),
|
311
|
+
help="Instance type, e.g. Interactive",
|
312
|
+
required=True,
|
313
|
+
)
|
314
|
+
@click.option(
|
315
|
+
"--container-name",
|
316
|
+
help="Docker container name [docker only]",
|
317
|
+
default=INTERACTIVE_DOCKER_CONTAINER_NAME,
|
318
|
+
show_default=True,
|
319
|
+
required=False,
|
320
|
+
)
|
321
|
+
@click.option(
|
322
|
+
"-y",
|
323
|
+
"--yes",
|
324
|
+
is_flag=True,
|
325
|
+
default=False,
|
326
|
+
help="Do not ask for confirmation",
|
327
|
+
required=False,
|
328
|
+
)
|
329
|
+
def destroy(type, container_name, yes):
|
330
|
+
"""Destroy Flex Interactive instance"""
|
331
|
+
if yes or click.confirm(f"Do you want to destroy {container_name} instance?"):
|
332
|
+
cmd = []
|
333
|
+
if type == "interactive":
|
334
|
+
cmd = [
|
335
|
+
"docker",
|
336
|
+
"rm",
|
337
|
+
"-f",
|
338
|
+
container_name,
|
339
|
+
]
|
340
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
341
|
+
if result.returncode == 0:
|
342
|
+
click.secho("[SUCCESS] ", nl=False, fg="green", bold=True)
|
343
|
+
click.secho(result.stdout, bold=False)
|
344
|
+
else:
|
345
|
+
click.secho("[FAILED] ", nl=False, fg="red", bold=True)
|
346
|
+
click.secho(result.stderr, bold=False)
|
347
|
+
|
348
|
+
|
349
|
+
@instance.command
|
350
|
+
@click.option(
|
351
|
+
"--type",
|
352
|
+
type=click.Choice(["interactive"], case_sensitive=False),
|
353
|
+
help="Instance type, e.g. Interactive",
|
354
|
+
required=True,
|
355
|
+
)
|
356
|
+
def status(type):
|
357
|
+
"""Display instance status"""
|
358
|
+
cmd = []
|
359
|
+
if type == "interactive":
|
360
|
+
cmd = [
|
361
|
+
"docker",
|
362
|
+
"ps",
|
363
|
+
"-a",
|
364
|
+
"--filter",
|
365
|
+
f"label={INTERACTIVE_DOCKER_CONTAINER_LABEL}",
|
366
|
+
]
|
367
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
368
|
+
if result.returncode == 0:
|
369
|
+
click.secho("[SUCCESS]\n", fg="green", bold=True)
|
370
|
+
click.secho(result.stdout, bold=False)
|
371
|
+
else:
|
372
|
+
click.secho("[FAILED] ", nl=False, fg="red", bold=True)
|
373
|
+
click.secho(result.stderr, bold=False)
|
374
|
+
|
375
|
+
|
376
|
+
@cli.command()
|
377
|
+
@click.argument(
|
378
|
+
"type",
|
379
|
+
type=click.Choice(
|
380
|
+
[
|
381
|
+
"dev",
|
382
|
+
"dev-analytical",
|
383
|
+
"dev-analytical-java",
|
384
|
+
"dev-interactive",
|
385
|
+
"dev-learning",
|
386
|
+
],
|
387
|
+
case_sensitive=False,
|
388
|
+
),
|
389
|
+
required=True,
|
390
|
+
)
|
391
|
+
@click.option(
|
392
|
+
"--graphscope-repo",
|
393
|
+
required=False,
|
394
|
+
help="GraphScope code repo location.",
|
395
|
+
)
|
396
|
+
@click.option(
|
397
|
+
"--cn",
|
398
|
+
is_flag=True,
|
399
|
+
default=False,
|
400
|
+
help="Whether to use CN located mirrors to speed up download.",
|
401
|
+
)
|
402
|
+
@click.option(
|
403
|
+
"--install-prefix",
|
404
|
+
type=click.Path(),
|
405
|
+
default="/opt/graphscope",
|
406
|
+
show_default=True,
|
407
|
+
help="Specify the directory on disk to which the file will be installed",
|
408
|
+
)
|
409
|
+
@click.option(
|
410
|
+
"--v6d-version",
|
411
|
+
default=__v6d_version__,
|
412
|
+
show_default=True,
|
413
|
+
help="vineyard version",
|
414
|
+
)
|
415
|
+
@click.option(
|
416
|
+
"--no-v6d",
|
417
|
+
is_flag=True,
|
418
|
+
default=False,
|
419
|
+
help="Do not install vineyard, could be used with analytical type",
|
420
|
+
)
|
421
|
+
def install_deps(
|
422
|
+
type,
|
423
|
+
graphscope_repo,
|
424
|
+
cn,
|
425
|
+
install_prefix,
|
426
|
+
v6d_version,
|
427
|
+
no_v6d,
|
428
|
+
):
|
429
|
+
"""Install dependencies for building GraphScope."""
|
430
|
+
cmd = [
|
431
|
+
"bash",
|
432
|
+
"-e",
|
433
|
+
install_deps_script,
|
434
|
+
type,
|
435
|
+
"--install-prefix",
|
436
|
+
install_prefix,
|
437
|
+
"--v6d-version",
|
438
|
+
str(v6d_version),
|
439
|
+
]
|
440
|
+
if no_v6d:
|
441
|
+
cmd.append("--no-v6d")
|
442
|
+
if cn:
|
443
|
+
cmd.append("--cn")
|
444
|
+
sys.exit(run_shell_cmd(cmd, graphscope_repo))
|
445
|
+
|
446
|
+
|
447
|
+
if __name__ == "__main__":
|
448
|
+
cli()
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright 2024 Alibaba Group Holding Limited. All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
@@ -0,0 +1,234 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright 2024 Alibaba Group Holding Limited. All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
import click
|
20
|
+
import yaml
|
21
|
+
|
22
|
+
from graphscope.gsctl.impl import bind_datasource_in_batch
|
23
|
+
from graphscope.gsctl.impl import delete_job_by_id
|
24
|
+
from graphscope.gsctl.impl import get_datasource_by_id
|
25
|
+
from graphscope.gsctl.impl import get_graph_id_by_name
|
26
|
+
from graphscope.gsctl.impl import get_graph_name_by_id
|
27
|
+
from graphscope.gsctl.impl import get_job_by_id
|
28
|
+
from graphscope.gsctl.impl import list_graphs
|
29
|
+
from graphscope.gsctl.impl import list_jobs
|
30
|
+
from graphscope.gsctl.impl import submit_dataloading_job
|
31
|
+
from graphscope.gsctl.impl import switch_context
|
32
|
+
from graphscope.gsctl.impl import unbind_edge_datasource
|
33
|
+
from graphscope.gsctl.impl import unbind_vertex_datasource
|
34
|
+
from graphscope.gsctl.utils import TreeDisplay
|
35
|
+
from graphscope.gsctl.utils import err
|
36
|
+
from graphscope.gsctl.utils import info
|
37
|
+
from graphscope.gsctl.utils import is_valid_file_path
|
38
|
+
from graphscope.gsctl.utils import read_yaml_file
|
39
|
+
from graphscope.gsctl.utils import succ
|
40
|
+
from graphscope.gsctl.utils import terminal_display
|
41
|
+
|
42
|
+
|
43
|
+
@click.group()
|
44
|
+
def cli():
|
45
|
+
pass
|
46
|
+
|
47
|
+
|
48
|
+
@cli.group()
|
49
|
+
def create():
|
50
|
+
"""Create data source, loader job from file"""
|
51
|
+
pass
|
52
|
+
|
53
|
+
|
54
|
+
@cli.group()
|
55
|
+
def delete():
|
56
|
+
"""Delete data source, loader job by id"""
|
57
|
+
pass
|
58
|
+
|
59
|
+
|
60
|
+
@cli.group()
|
61
|
+
def desc():
|
62
|
+
"""Show job's details by id"""
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
@cli.command()
|
67
|
+
@click.argument(
|
68
|
+
"context", type=click.Choice(["GRAPH"], case_sensitive=False), required=True
|
69
|
+
)
|
70
|
+
@click.argument("GRAPH_IDENTIFIER", required=True)
|
71
|
+
def use(context, graph_identifier):
|
72
|
+
"""Switch to GRAPH context, see identifier with `ls` command"""
|
73
|
+
try:
|
74
|
+
graph_identifier = get_graph_id_by_name(graph_identifier)
|
75
|
+
graph_name = get_graph_name_by_id(graph_identifier)
|
76
|
+
switch_context(graph_identifier, graph_name)
|
77
|
+
except Exception as e:
|
78
|
+
err(f"Failed to switch context: {str(e)}")
|
79
|
+
else:
|
80
|
+
click.secho(f"Using GRAPH {graph_name}(id={graph_identifier})", fg="green")
|
81
|
+
|
82
|
+
|
83
|
+
@cli.command()
|
84
|
+
@click.option("-l", is_flag=True, help="List sub resources recursively")
|
85
|
+
def ls(l): # noqa: F811, E741
|
86
|
+
"""Display graph resources in database"""
|
87
|
+
tree = TreeDisplay()
|
88
|
+
try:
|
89
|
+
graphs = list_graphs()
|
90
|
+
for g in graphs:
|
91
|
+
# schema
|
92
|
+
tree.create_graph_node(g, recursive=l)
|
93
|
+
if l:
|
94
|
+
# data source mapping
|
95
|
+
datasource_mapping = get_datasource_by_id(g.id)
|
96
|
+
tree.create_datasource_mapping_node(g, datasource_mapping)
|
97
|
+
# job
|
98
|
+
jobs = list_jobs()
|
99
|
+
tree.create_job_node(g, jobs)
|
100
|
+
except Exception as e:
|
101
|
+
err(f"Failed to list resources: {str(e)}")
|
102
|
+
else:
|
103
|
+
tree.show()
|
104
|
+
if not l:
|
105
|
+
info("Run `gsctl ls -l` to list all resources recursively.")
|
106
|
+
|
107
|
+
|
108
|
+
@create.command()
|
109
|
+
@click.option(
|
110
|
+
"-g",
|
111
|
+
"--graph_identifier",
|
112
|
+
required=True,
|
113
|
+
help="See graph identifier with `ls` command",
|
114
|
+
)
|
115
|
+
@click.option(
|
116
|
+
"-f",
|
117
|
+
"--filename",
|
118
|
+
required=True,
|
119
|
+
help="Path of yaml file",
|
120
|
+
)
|
121
|
+
def datasource(graph_identifier, filename): # noqa: F811
|
122
|
+
"""Bind data source mapping from file"""
|
123
|
+
if not is_valid_file_path(filename):
|
124
|
+
err(f"Invalid file: {filename}")
|
125
|
+
return
|
126
|
+
graph_identifier = get_graph_id_by_name(graph_identifier)
|
127
|
+
try:
|
128
|
+
datasource = read_yaml_file(filename)
|
129
|
+
bind_datasource_in_batch(graph_identifier, datasource)
|
130
|
+
except Exception as e:
|
131
|
+
err(f"Failed to bind data source: {str(e)}")
|
132
|
+
else:
|
133
|
+
succ("Bind data source successfully.")
|
134
|
+
|
135
|
+
|
136
|
+
@delete.command
|
137
|
+
@click.option(
|
138
|
+
"-g",
|
139
|
+
"--graph_identifier",
|
140
|
+
required=True,
|
141
|
+
help="See graph identifier with `ls` command",
|
142
|
+
)
|
143
|
+
@click.option(
|
144
|
+
"-t",
|
145
|
+
"--type",
|
146
|
+
required=True,
|
147
|
+
help="Vertex or edge type",
|
148
|
+
)
|
149
|
+
@click.option(
|
150
|
+
"-s",
|
151
|
+
"--source_vertex_type",
|
152
|
+
required=False,
|
153
|
+
help="Source vertex type of the edge [edge only]",
|
154
|
+
)
|
155
|
+
@click.option(
|
156
|
+
"-d",
|
157
|
+
"--destination_vertex_type",
|
158
|
+
required=False,
|
159
|
+
help="Destination vertex type of the edge [edge only]",
|
160
|
+
)
|
161
|
+
def datasource( # noqa: F811
|
162
|
+
graph_identifier, type, source_vertex_type, destination_vertex_type
|
163
|
+
):
|
164
|
+
"""Unbind data source mapping on vertex or edge type"""
|
165
|
+
try:
|
166
|
+
graph_identifier = get_graph_id_by_name(graph_identifier)
|
167
|
+
if source_vertex_type is not None and destination_vertex_type is not None:
|
168
|
+
unbind_edge_datasource(
|
169
|
+
graph_identifier, type, source_vertex_type, destination_vertex_type
|
170
|
+
)
|
171
|
+
else:
|
172
|
+
unbind_vertex_datasource(graph_identifier, type)
|
173
|
+
except Exception as e:
|
174
|
+
err(f"Failed to unbind data source: {str(e)}")
|
175
|
+
else:
|
176
|
+
succ("Unbind data source successfully.")
|
177
|
+
|
178
|
+
|
179
|
+
@create.command()
|
180
|
+
@click.option(
|
181
|
+
"-g",
|
182
|
+
"--graph_identifier",
|
183
|
+
required=True,
|
184
|
+
help="See graph identifier with `ls` command",
|
185
|
+
)
|
186
|
+
@click.option(
|
187
|
+
"-f",
|
188
|
+
"--filename",
|
189
|
+
required=True,
|
190
|
+
help="Path of yaml file",
|
191
|
+
)
|
192
|
+
def loaderjob(graph_identifier, filename): # noqa: F811
|
193
|
+
"""Create a data loading job from file"""
|
194
|
+
if not is_valid_file_path(filename):
|
195
|
+
err(f"Invalid file: {filename}")
|
196
|
+
return
|
197
|
+
graph_identifier = get_graph_id_by_name(graph_identifier)
|
198
|
+
try:
|
199
|
+
config = read_yaml_file(filename)
|
200
|
+
jobid = submit_dataloading_job(graph_identifier, config)
|
201
|
+
except Exception as e:
|
202
|
+
err(f"Failed to create a job: {str(e)}")
|
203
|
+
else:
|
204
|
+
succ(f"Create job {jobid} successfully.")
|
205
|
+
|
206
|
+
|
207
|
+
@desc.command()
|
208
|
+
@click.argument("identifier", required=True)
|
209
|
+
def job(identifier): # noqa: F811
|
210
|
+
"""Show details of job, see identifier with `ls` command"""
|
211
|
+
try:
|
212
|
+
job = get_job_by_id(identifier)
|
213
|
+
except Exception as e:
|
214
|
+
err(f"Failed to get job: {str(e)}")
|
215
|
+
else:
|
216
|
+
info(yaml.dump(job.to_dict()))
|
217
|
+
|
218
|
+
|
219
|
+
@delete.command()
|
220
|
+
@click.argument("identifier", required=True)
|
221
|
+
@click.option(
|
222
|
+
"--delete-scheduler",
|
223
|
+
is_flag=True,
|
224
|
+
default=False,
|
225
|
+
help="Whether to delete the job scheduler or not",
|
226
|
+
)
|
227
|
+
def job(identifier, delete_scheduler): # noqa: F811
|
228
|
+
"""Cancel a job, see identifier with `ls` command"""
|
229
|
+
try:
|
230
|
+
if click.confirm("Do you want to continue?"):
|
231
|
+
delete_job_by_id(identifier, delete_scheduler)
|
232
|
+
succ(f"Cancel job {identifier} successfully.")
|
233
|
+
except Exception as e:
|
234
|
+
err(f"Failed to Cancel job {identifier}: {str(e)}")
|