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.
Files changed (117) hide show
  1. graphscope/flex/rest/__init__.py +106 -0
  2. graphscope/flex/rest/api/__init__.py +12 -0
  3. graphscope/flex/rest/api/alert_api.py +2790 -0
  4. graphscope/flex/rest/api/data_source_api.py +1177 -0
  5. graphscope/flex/rest/api/deployment_api.py +1323 -0
  6. graphscope/flex/rest/api/graph_api.py +2813 -0
  7. graphscope/flex/rest/api/job_api.py +1408 -0
  8. graphscope/flex/rest/api/service_api.py +1316 -0
  9. graphscope/flex/rest/api/stored_procedure_api.py +1454 -0
  10. graphscope/flex/rest/api/utils_api.py +310 -0
  11. graphscope/flex/rest/api_client.py +789 -0
  12. graphscope/flex/rest/api_response.py +21 -0
  13. graphscope/flex/rest/configuration.py +451 -0
  14. graphscope/flex/rest/exceptions.py +200 -0
  15. graphscope/flex/rest/models/__init__.py +82 -0
  16. graphscope/flex/rest/models/base_edge_type.py +102 -0
  17. graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner.py +108 -0
  18. graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner_x_csr_params.py +98 -0
  19. graphscope/flex/rest/models/base_property_meta.py +105 -0
  20. graphscope/flex/rest/models/base_vertex_type.py +96 -0
  21. graphscope/flex/rest/models/base_vertex_type_x_csr_params.py +88 -0
  22. graphscope/flex/rest/models/column_mapping.py +94 -0
  23. graphscope/flex/rest/models/column_mapping_column.py +90 -0
  24. graphscope/flex/rest/models/create_alert_receiver_request.py +103 -0
  25. graphscope/flex/rest/models/create_alert_rule_request.py +112 -0
  26. graphscope/flex/rest/models/create_dataloading_job_response.py +88 -0
  27. graphscope/flex/rest/models/create_edge_type.py +114 -0
  28. graphscope/flex/rest/models/create_graph_request.py +106 -0
  29. graphscope/flex/rest/models/create_graph_response.py +88 -0
  30. graphscope/flex/rest/models/create_graph_schema_request.py +106 -0
  31. graphscope/flex/rest/models/create_property_meta.py +105 -0
  32. graphscope/flex/rest/models/create_stored_proc_request.py +101 -0
  33. graphscope/flex/rest/models/create_stored_proc_response.py +88 -0
  34. graphscope/flex/rest/models/create_vertex_type.py +108 -0
  35. graphscope/flex/rest/models/dataloading_job_config.py +136 -0
  36. graphscope/flex/rest/models/dataloading_job_config_edges_inner.py +92 -0
  37. graphscope/flex/rest/models/dataloading_job_config_loading_config.py +104 -0
  38. graphscope/flex/rest/models/dataloading_job_config_loading_config_format.py +90 -0
  39. graphscope/flex/rest/models/dataloading_job_config_vertices_inner.py +88 -0
  40. graphscope/flex/rest/models/dataloading_mr_job_config.py +88 -0
  41. graphscope/flex/rest/models/date_type.py +88 -0
  42. graphscope/flex/rest/models/edge_mapping.py +122 -0
  43. graphscope/flex/rest/models/edge_mapping_type_triplet.py +92 -0
  44. graphscope/flex/rest/models/error.py +90 -0
  45. graphscope/flex/rest/models/get_alert_message_response.py +123 -0
  46. graphscope/flex/rest/models/get_alert_receiver_response.py +107 -0
  47. graphscope/flex/rest/models/get_alert_rule_response.py +114 -0
  48. graphscope/flex/rest/models/get_edge_type.py +116 -0
  49. graphscope/flex/rest/models/get_graph_response.py +139 -0
  50. graphscope/flex/rest/models/get_graph_schema_response.py +106 -0
  51. graphscope/flex/rest/models/get_pod_log_response.py +88 -0
  52. graphscope/flex/rest/models/get_property_meta.py +107 -0
  53. graphscope/flex/rest/models/get_resource_usage_response.py +105 -0
  54. graphscope/flex/rest/models/get_storage_usage_response.py +88 -0
  55. graphscope/flex/rest/models/get_stored_proc_response.py +130 -0
  56. graphscope/flex/rest/models/get_vertex_type.py +110 -0
  57. graphscope/flex/rest/models/gs_data_type.py +152 -0
  58. graphscope/flex/rest/models/job_status.py +107 -0
  59. graphscope/flex/rest/models/long_text.py +93 -0
  60. graphscope/flex/rest/models/node_status.py +94 -0
  61. graphscope/flex/rest/models/parameter.py +96 -0
  62. graphscope/flex/rest/models/pod_status.py +108 -0
  63. graphscope/flex/rest/models/primitive_type.py +95 -0
  64. graphscope/flex/rest/models/resource_usage.py +92 -0
  65. graphscope/flex/rest/models/running_deployment_info.py +128 -0
  66. graphscope/flex/rest/models/running_deployment_status.py +124 -0
  67. graphscope/flex/rest/models/schema_mapping.py +106 -0
  68. graphscope/flex/rest/models/service_status.py +112 -0
  69. graphscope/flex/rest/models/service_status_sdk_endpoints.py +94 -0
  70. graphscope/flex/rest/models/start_service_request.py +88 -0
  71. graphscope/flex/rest/models/stored_procedure_meta.py +126 -0
  72. graphscope/flex/rest/models/string_type.py +92 -0
  73. graphscope/flex/rest/models/string_type_string.py +124 -0
  74. graphscope/flex/rest/models/temporal_type.py +92 -0
  75. graphscope/flex/rest/models/temporal_type_temporal.py +138 -0
  76. graphscope/flex/rest/models/time_stamp_type.py +88 -0
  77. graphscope/flex/rest/models/update_alert_message_status_request.py +97 -0
  78. graphscope/flex/rest/models/update_stored_proc_request.py +88 -0
  79. graphscope/flex/rest/models/upload_file_response.py +90 -0
  80. graphscope/flex/rest/models/vertex_mapping.py +100 -0
  81. graphscope/flex/rest/py.typed +0 -0
  82. graphscope/flex/rest/rest.py +258 -0
  83. graphscope/gsctl/V6D_VERSION +1 -0
  84. graphscope/gsctl/VERSION +1 -0
  85. graphscope/gsctl/__init__.py +22 -0
  86. graphscope/gsctl/commands/__init__.py +148 -0
  87. graphscope/gsctl/commands/common.py +200 -0
  88. graphscope/gsctl/commands/dev.py +448 -0
  89. graphscope/gsctl/commands/insight/__init__.py +17 -0
  90. graphscope/gsctl/commands/insight/glob.py +234 -0
  91. graphscope/gsctl/commands/insight/graph.py +205 -0
  92. graphscope/gsctl/commands/interactive/__init__.py +17 -0
  93. graphscope/gsctl/commands/interactive/glob.py +280 -0
  94. graphscope/gsctl/commands/interactive/graph.py +259 -0
  95. graphscope/gsctl/config.py +221 -0
  96. graphscope/gsctl/gsctl.py +51 -0
  97. graphscope/gsctl/impl/__init__.py +64 -0
  98. graphscope/gsctl/impl/alert.py +135 -0
  99. graphscope/gsctl/impl/common.py +53 -0
  100. graphscope/gsctl/impl/datasource.py +80 -0
  101. graphscope/gsctl/impl/deployment.py +62 -0
  102. graphscope/gsctl/impl/graph.py +150 -0
  103. graphscope/gsctl/impl/job.py +63 -0
  104. graphscope/gsctl/impl/service.py +62 -0
  105. graphscope/gsctl/impl/stored_procedure.py +92 -0
  106. graphscope/gsctl/impl/utils.py +38 -0
  107. graphscope/gsctl/scripts/install_deps.sh +969 -0
  108. graphscope/gsctl/tests/__init__.py +17 -0
  109. graphscope/gsctl/tests/test_graphscope_insight.py +401 -0
  110. graphscope/gsctl/tests/test_interactive.py +516 -0
  111. graphscope/gsctl/utils.py +337 -0
  112. graphscope/gsctl/version.py +31 -0
  113. gsctl-0.29.0a20250114.dist-info/METADATA +20 -0
  114. gsctl-0.29.0a20250114.dist-info/RECORD +117 -0
  115. gsctl-0.29.0a20250114.dist-info/WHEEL +6 -0
  116. gsctl-0.29.0a20250114.dist-info/entry_points.txt +3 -0
  117. 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)}")