snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 2.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- README.md +21 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/METADATA +7 -95
- snowflake_cli_labs-2.8.2.dist-info/RECORD +5 -0
- snowflake/cli/__about__.py +0 -17
- snowflake/cli/__init__.py +0 -13
- snowflake/cli/api/__init__.py +0 -48
- snowflake/cli/api/cli_global_context.py +0 -390
- snowflake/cli/api/commands/__init__.py +0 -13
- snowflake/cli/api/commands/alias.py +0 -23
- snowflake/cli/api/commands/decorators.py +0 -354
- snowflake/cli/api/commands/execution_metadata.py +0 -40
- snowflake/cli/api/commands/experimental_behaviour.py +0 -19
- snowflake/cli/api/commands/flags.py +0 -640
- snowflake/cli/api/commands/project_initialisation.py +0 -65
- snowflake/cli/api/commands/snow_typer.py +0 -237
- snowflake/cli/api/commands/typer_pre_execute.py +0 -26
- snowflake/cli/api/config.py +0 -348
- snowflake/cli/api/console/__init__.py +0 -17
- snowflake/cli/api/console/abc.py +0 -89
- snowflake/cli/api/console/console.py +0 -134
- snowflake/cli/api/console/enum.py +0 -17
- snowflake/cli/api/constants.py +0 -79
- snowflake/cli/api/errno.py +0 -27
- snowflake/cli/api/exceptions.py +0 -164
- snowflake/cli/api/feature_flags.py +0 -55
- snowflake/cli/api/identifiers.py +0 -154
- snowflake/cli/api/output/__init__.py +0 -13
- snowflake/cli/api/output/formats.py +0 -20
- snowflake/cli/api/output/types.py +0 -118
- snowflake/cli/api/plugins/__init__.py +0 -13
- snowflake/cli/api/plugins/command/__init__.py +0 -72
- snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
- snowflake/cli/api/plugins/plugin_config.py +0 -32
- snowflake/cli/api/project/__init__.py +0 -13
- snowflake/cli/api/project/definition.py +0 -84
- snowflake/cli/api/project/definition_manager.py +0 -134
- snowflake/cli/api/project/errors.py +0 -56
- snowflake/cli/api/project/project_verification.py +0 -23
- snowflake/cli/api/project/schemas/__init__.py +0 -13
- snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
- snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
- snowflake/cli/api/project/schemas/entities/common.py +0 -78
- snowflake/cli/api/project/schemas/entities/entities.py +0 -30
- snowflake/cli/api/project/schemas/identifier_model.py +0 -49
- snowflake/cli/api/project/schemas/native_app/__init__.py +0 -13
- snowflake/cli/api/project/schemas/native_app/application.py +0 -62
- snowflake/cli/api/project/schemas/native_app/native_app.py +0 -93
- snowflake/cli/api/project/schemas/native_app/package.py +0 -78
- snowflake/cli/api/project/schemas/native_app/path_mapping.py +0 -65
- snowflake/cli/api/project/schemas/project_definition.py +0 -199
- snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
- snowflake/cli/api/project/schemas/snowpark/argument.py +0 -28
- snowflake/cli/api/project/schemas/snowpark/callable.py +0 -69
- snowflake/cli/api/project/schemas/snowpark/snowpark.py +0 -36
- snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
- snowflake/cli/api/project/schemas/streamlit/streamlit.py +0 -46
- snowflake/cli/api/project/schemas/template.py +0 -77
- snowflake/cli/api/project/schemas/updatable_model.py +0 -194
- snowflake/cli/api/project/util.py +0 -261
- snowflake/cli/api/rendering/__init__.py +0 -13
- snowflake/cli/api/rendering/jinja.py +0 -112
- snowflake/cli/api/rendering/project_definition_templates.py +0 -39
- snowflake/cli/api/rendering/project_templates.py +0 -98
- snowflake/cli/api/rendering/sql_templates.py +0 -60
- snowflake/cli/api/rest_api.py +0 -172
- snowflake/cli/api/sanitizers.py +0 -43
- snowflake/cli/api/secure_path.py +0 -362
- snowflake/cli/api/secure_utils.py +0 -29
- snowflake/cli/api/sql_execution.py +0 -260
- snowflake/cli/api/utils/__init__.py +0 -13
- snowflake/cli/api/utils/cursor.py +0 -34
- snowflake/cli/api/utils/definition_rendering.py +0 -383
- snowflake/cli/api/utils/dict_utils.py +0 -73
- snowflake/cli/api/utils/error_handling.py +0 -23
- snowflake/cli/api/utils/graph.py +0 -97
- snowflake/cli/api/utils/models.py +0 -63
- snowflake/cli/api/utils/naming_utils.py +0 -13
- snowflake/cli/api/utils/path_utils.py +0 -36
- snowflake/cli/api/utils/templating_functions.py +0 -144
- snowflake/cli/api/utils/types.py +0 -35
- snowflake/cli/app/__init__.py +0 -22
- snowflake/cli/app/__main__.py +0 -31
- snowflake/cli/app/api_impl/__init__.py +0 -13
- snowflake/cli/app/api_impl/plugin/__init__.py +0 -13
- snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
- snowflake/cli/app/build_and_push.sh +0 -8
- snowflake/cli/app/cli_app.py +0 -243
- snowflake/cli/app/commands_registration/__init__.py +0 -33
- snowflake/cli/app/commands_registration/builtin_plugins.py +0 -54
- snowflake/cli/app/commands_registration/command_plugins_loader.py +0 -169
- snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +0 -105
- snowflake/cli/app/commands_registration/exception_logging.py +0 -26
- snowflake/cli/app/commands_registration/threadsafe.py +0 -48
- snowflake/cli/app/commands_registration/typer_registration.py +0 -153
- snowflake/cli/app/constants.py +0 -19
- snowflake/cli/app/dev/__init__.py +0 -13
- snowflake/cli/app/dev/commands_structure.py +0 -48
- snowflake/cli/app/dev/docs/__init__.py +0 -13
- snowflake/cli/app/dev/docs/commands_docs_generator.py +0 -100
- snowflake/cli/app/dev/docs/generator.py +0 -35
- snowflake/cli/app/dev/docs/project_definition_docs_generator.py +0 -58
- snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +0 -227
- snowflake/cli/app/dev/docs/template_utils.py +0 -23
- snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
- snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +0 -9
- snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +0 -57
- snowflake/cli/app/dev/pycharm_remote_debug.py +0 -46
- snowflake/cli/app/loggers.py +0 -199
- snowflake/cli/app/main_typer.py +0 -62
- snowflake/cli/app/printing.py +0 -181
- snowflake/cli/app/snow_connector.py +0 -243
- snowflake/cli/app/telemetry.py +0 -189
- snowflake/cli/plugins/__init__.py +0 -13
- snowflake/cli/plugins/connection/__init__.py +0 -13
- snowflake/cli/plugins/connection/commands.py +0 -330
- snowflake/cli/plugins/connection/plugin_spec.py +0 -30
- snowflake/cli/plugins/connection/util.py +0 -179
- snowflake/cli/plugins/cortex/__init__.py +0 -13
- snowflake/cli/plugins/cortex/commands.py +0 -327
- snowflake/cli/plugins/cortex/constants.py +0 -17
- snowflake/cli/plugins/cortex/manager.py +0 -189
- snowflake/cli/plugins/cortex/plugin_spec.py +0 -30
- snowflake/cli/plugins/cortex/types.py +0 -22
- snowflake/cli/plugins/git/__init__.py +0 -13
- snowflake/cli/plugins/git/commands.py +0 -305
- snowflake/cli/plugins/git/manager.py +0 -96
- snowflake/cli/plugins/git/plugin_spec.py +0 -30
- snowflake/cli/plugins/init/__init__.py +0 -13
- snowflake/cli/plugins/init/commands.py +0 -244
- snowflake/cli/plugins/init/plugin_spec.py +0 -30
- snowflake/cli/plugins/nativeapp/__init__.py +0 -13
- snowflake/cli/plugins/nativeapp/artifacts.py +0 -742
- snowflake/cli/plugins/nativeapp/codegen/__init__.py +0 -13
- snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +0 -91
- snowflake/cli/plugins/nativeapp/codegen/compiler.py +0 -130
- snowflake/cli/plugins/nativeapp/codegen/sandbox.py +0 -306
- snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
- snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -56
- snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
- snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
- snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +0 -61
- snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +0 -528
- snowflake/cli/plugins/nativeapp/commands.py +0 -439
- snowflake/cli/plugins/nativeapp/common_flags.py +0 -44
- snowflake/cli/plugins/nativeapp/constants.py +0 -27
- snowflake/cli/plugins/nativeapp/exceptions.py +0 -122
- snowflake/cli/plugins/nativeapp/feature_flags.py +0 -24
- snowflake/cli/plugins/nativeapp/init.py +0 -345
- snowflake/cli/plugins/nativeapp/manager.py +0 -823
- snowflake/cli/plugins/nativeapp/plugin_spec.py +0 -30
- snowflake/cli/plugins/nativeapp/policy.py +0 -50
- snowflake/cli/plugins/nativeapp/project_model.py +0 -195
- snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
- snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
- snowflake/cli/plugins/nativeapp/utils.py +0 -98
- snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
- snowflake/cli/plugins/nativeapp/version/__init__.py +0 -13
- snowflake/cli/plugins/nativeapp/version/commands.py +0 -170
- snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
- snowflake/cli/plugins/notebook/__init__.py +0 -13
- snowflake/cli/plugins/notebook/commands.py +0 -84
- snowflake/cli/plugins/notebook/exceptions.py +0 -20
- snowflake/cli/plugins/notebook/manager.py +0 -71
- snowflake/cli/plugins/notebook/plugin_spec.py +0 -30
- snowflake/cli/plugins/notebook/types.py +0 -16
- snowflake/cli/plugins/object/__init__.py +0 -13
- snowflake/cli/plugins/object/command_aliases.py +0 -94
- snowflake/cli/plugins/object/commands.py +0 -174
- snowflake/cli/plugins/object/common.py +0 -85
- snowflake/cli/plugins/object/manager.py +0 -96
- snowflake/cli/plugins/object/plugin_spec.py +0 -30
- snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
- snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
- snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
- snowflake/cli/plugins/snowpark/__init__.py +0 -13
- snowflake/cli/plugins/snowpark/commands.py +0 -548
- snowflake/cli/plugins/snowpark/common.py +0 -307
- snowflake/cli/plugins/snowpark/manager.py +0 -109
- snowflake/cli/plugins/snowpark/models.py +0 -156
- snowflake/cli/plugins/snowpark/package/__init__.py +0 -13
- snowflake/cli/plugins/snowpark/package/anaconda_packages.py +0 -233
- snowflake/cli/plugins/snowpark/package/commands.py +0 -256
- snowflake/cli/plugins/snowpark/package/manager.py +0 -43
- snowflake/cli/plugins/snowpark/package/utils.py +0 -26
- snowflake/cli/plugins/snowpark/package_utils.py +0 -354
- snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
- snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
- snowflake/cli/plugins/snowpark/snowpark_shared.py +0 -95
- snowflake/cli/plugins/snowpark/zipper.py +0 -81
- snowflake/cli/plugins/spcs/__init__.py +0 -35
- snowflake/cli/plugins/spcs/common.py +0 -99
- snowflake/cli/plugins/spcs/compute_pool/__init__.py +0 -13
- snowflake/cli/plugins/spcs/compute_pool/commands.py +0 -240
- snowflake/cli/plugins/spcs/compute_pool/manager.py +0 -121
- snowflake/cli/plugins/spcs/image_registry/__init__.py +0 -13
- snowflake/cli/plugins/spcs/image_registry/commands.py +0 -65
- snowflake/cli/plugins/spcs/image_registry/manager.py +0 -105
- snowflake/cli/plugins/spcs/image_repository/__init__.py +0 -13
- snowflake/cli/plugins/spcs/image_repository/commands.py +0 -196
- snowflake/cli/plugins/spcs/image_repository/manager.py +0 -84
- snowflake/cli/plugins/spcs/jobs/__init__.py +0 -13
- snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
- snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
- snowflake/cli/plugins/spcs/plugin_spec.py +0 -30
- snowflake/cli/plugins/spcs/services/__init__.py +0 -13
- snowflake/cli/plugins/spcs/services/commands.py +0 -311
- snowflake/cli/plugins/spcs/services/manager.py +0 -170
- snowflake/cli/plugins/sql/__init__.py +0 -13
- snowflake/cli/plugins/sql/commands.py +0 -83
- snowflake/cli/plugins/sql/manager.py +0 -92
- snowflake/cli/plugins/sql/plugin_spec.py +0 -30
- snowflake/cli/plugins/sql/snowsql_templating.py +0 -28
- snowflake/cli/plugins/stage/__init__.py +0 -13
- snowflake/cli/plugins/stage/commands.py +0 -261
- snowflake/cli/plugins/stage/diff.py +0 -326
- snowflake/cli/plugins/stage/manager.py +0 -544
- snowflake/cli/plugins/stage/md5.py +0 -160
- snowflake/cli/plugins/stage/plugin_spec.py +0 -30
- snowflake/cli/plugins/streamlit/__init__.py +0 -13
- snowflake/cli/plugins/streamlit/commands.py +0 -186
- snowflake/cli/plugins/streamlit/manager.py +0 -222
- snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/plugins/workspace/__init__.py +0 -13
- snowflake/cli/plugins/workspace/commands.py +0 -35
- snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
- snowflake/cli/templates/default_snowpark/.gitignore +0 -4
- snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
- snowflake/cli/templates/default_snowpark/app/common.py +0 -2
- snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
- snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
- snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
- snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
- snowflake/cli/templates/default_streamlit/.gitignore +0 -4
- snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
- snowflake/cli/templates/default_streamlit/environment.yml +0 -6
- snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
- snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
- snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
- snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
- snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import sys
|
|
18
|
-
from typing import TextIO
|
|
19
|
-
|
|
20
|
-
from click import ClickException
|
|
21
|
-
from snowflake.cli.api.constants import ObjectType
|
|
22
|
-
from snowflake.cli.api.exceptions import ObjectAlreadyExistsError
|
|
23
|
-
from snowflake.cli.api.project.util import unquote_identifier
|
|
24
|
-
from snowflake.connector.errors import ProgrammingError
|
|
25
|
-
|
|
26
|
-
if not sys.stdout.closed and sys.stdout.isatty():
|
|
27
|
-
GREEN = "\033[32m"
|
|
28
|
-
BLUE = "\033[34m"
|
|
29
|
-
ORANGE = "\033[38:2:238:76:44m"
|
|
30
|
-
GRAY = "\033[2m"
|
|
31
|
-
ENDC = "\033[0m"
|
|
32
|
-
else:
|
|
33
|
-
GREEN = ""
|
|
34
|
-
ORANGE = ""
|
|
35
|
-
BLUE = ""
|
|
36
|
-
GRAY = ""
|
|
37
|
-
ENDC = ""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def _prefix_line(prefix: str, line: str) -> str:
|
|
41
|
-
"""
|
|
42
|
-
_prefix_line ensure the prefix is still present even when dealing with return characters
|
|
43
|
-
"""
|
|
44
|
-
if "\r" in line:
|
|
45
|
-
line = line.replace("\r", f"\r{prefix}")
|
|
46
|
-
if "\n" in line[:-1]:
|
|
47
|
-
line = line[:-1].replace("\n", f"\n{prefix}") + line[-1:]
|
|
48
|
-
if not line.startswith("\r"):
|
|
49
|
-
line = f"{prefix}{line}"
|
|
50
|
-
return line
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def print_log_lines(file: TextIO, name, identifier, logs):
|
|
54
|
-
prefix = f"{GREEN}{name}/{identifier}{ENDC} "
|
|
55
|
-
logs = logs[0:-1]
|
|
56
|
-
for log in logs:
|
|
57
|
-
print(_prefix_line(prefix, log + "\n"), file=file, end="", flush=True)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def strip_empty_lines(lines: list[str]) -> str:
|
|
61
|
-
return "\n".join(stripped for l in lines if (stripped := l.strip()))
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def validate_and_set_instances(min_instances, max_instances, instance_name):
|
|
65
|
-
"""
|
|
66
|
-
Used to validate that min_instances is positive and that max_instances is not less than min_instances. In the
|
|
67
|
-
case that max_instances is none, sets it equal to min_instances by default. Used like `max_instances =
|
|
68
|
-
validate_and_set_instances(min_instances, max_instances, "name")`.
|
|
69
|
-
"""
|
|
70
|
-
if min_instances < 1:
|
|
71
|
-
raise ClickException(f"min_{instance_name} must be positive")
|
|
72
|
-
|
|
73
|
-
if max_instances is None:
|
|
74
|
-
max_instances = min_instances
|
|
75
|
-
elif max_instances < min_instances:
|
|
76
|
-
raise ClickException(
|
|
77
|
-
f"max_{instance_name} must be greater or equal to min_{instance_name}"
|
|
78
|
-
)
|
|
79
|
-
return max_instances
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def handle_object_already_exists(
|
|
83
|
-
error: ProgrammingError,
|
|
84
|
-
object_type: ObjectType,
|
|
85
|
-
object_name: str,
|
|
86
|
-
replace_available: bool = False,
|
|
87
|
-
):
|
|
88
|
-
if error.errno == 2002:
|
|
89
|
-
raise ObjectAlreadyExistsError(
|
|
90
|
-
object_type=object_type,
|
|
91
|
-
name=unquote_identifier(object_name),
|
|
92
|
-
replace_available=replace_available,
|
|
93
|
-
)
|
|
94
|
-
else:
|
|
95
|
-
raise error
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class NoPropertiesProvidedError(ClickException):
|
|
99
|
-
pass
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
from typing import Optional
|
|
18
|
-
|
|
19
|
-
import typer
|
|
20
|
-
from click import ClickException
|
|
21
|
-
from snowflake.cli.api.commands.flags import (
|
|
22
|
-
IfNotExistsOption,
|
|
23
|
-
OverrideableOption,
|
|
24
|
-
like_option,
|
|
25
|
-
)
|
|
26
|
-
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
27
|
-
from snowflake.cli.api.constants import ObjectType
|
|
28
|
-
from snowflake.cli.api.output.types import CommandResult, SingleQueryResult
|
|
29
|
-
from snowflake.cli.api.project.util import is_valid_object_name
|
|
30
|
-
from snowflake.cli.plugins.object.command_aliases import (
|
|
31
|
-
add_object_command_aliases,
|
|
32
|
-
)
|
|
33
|
-
from snowflake.cli.plugins.object.common import CommentOption
|
|
34
|
-
from snowflake.cli.plugins.spcs.common import (
|
|
35
|
-
validate_and_set_instances,
|
|
36
|
-
)
|
|
37
|
-
from snowflake.cli.plugins.spcs.compute_pool.manager import ComputePoolManager
|
|
38
|
-
|
|
39
|
-
app = SnowTyperFactory(
|
|
40
|
-
name="compute-pool",
|
|
41
|
-
help="Manages Snowpark Container Services compute pools.",
|
|
42
|
-
short_help="Manages compute pools.",
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _compute_pool_name_callback(name: str) -> str:
|
|
47
|
-
"""
|
|
48
|
-
Verifies that compute pool name is a single valid identifier.
|
|
49
|
-
"""
|
|
50
|
-
if not is_valid_object_name(name, max_depth=0, allow_quoted=False):
|
|
51
|
-
raise ClickException(
|
|
52
|
-
f"'{name}' is not a valid compute pool name. Note that compute pool names must be unquoted identifiers."
|
|
53
|
-
)
|
|
54
|
-
return name
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
ComputePoolNameArgument = typer.Argument(
|
|
58
|
-
...,
|
|
59
|
-
help="Name of the compute pool.",
|
|
60
|
-
callback=_compute_pool_name_callback,
|
|
61
|
-
show_default=False,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
MinNodesOption = OverrideableOption(
|
|
66
|
-
1,
|
|
67
|
-
"--min-nodes",
|
|
68
|
-
help="Minimum number of nodes for the compute pool.",
|
|
69
|
-
min=1,
|
|
70
|
-
)
|
|
71
|
-
MaxNodesOption = OverrideableOption(
|
|
72
|
-
None,
|
|
73
|
-
"--max-nodes",
|
|
74
|
-
help="Maximum number of nodes for the compute pool.",
|
|
75
|
-
min=1,
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
_AUTO_RESUME_HELP = "The compute pool will automatically resume when a service or job is submitted to it."
|
|
79
|
-
|
|
80
|
-
AutoResumeOption = OverrideableOption(
|
|
81
|
-
True,
|
|
82
|
-
"--auto-resume/--no-auto-resume",
|
|
83
|
-
help=_AUTO_RESUME_HELP,
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
_AUTO_SUSPEND_SECS_HELP = "Number of seconds of inactivity after which you want Snowflake to automatically suspend the compute pool."
|
|
87
|
-
AutoSuspendSecsOption = OverrideableOption(
|
|
88
|
-
3600,
|
|
89
|
-
"--auto-suspend-secs",
|
|
90
|
-
help=_AUTO_SUSPEND_SECS_HELP,
|
|
91
|
-
min=1,
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
_COMMENT_HELP = "Comment for the compute pool."
|
|
95
|
-
|
|
96
|
-
add_object_command_aliases(
|
|
97
|
-
app=app,
|
|
98
|
-
object_type=ObjectType.COMPUTE_POOL,
|
|
99
|
-
name_argument=ComputePoolNameArgument,
|
|
100
|
-
like_option=like_option(
|
|
101
|
-
help_example='`list --like "my%"` lists all compute pools that begin with “my”.'
|
|
102
|
-
),
|
|
103
|
-
scope_option=None,
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@app.command(requires_connection=True)
|
|
108
|
-
def create(
|
|
109
|
-
name: str = ComputePoolNameArgument,
|
|
110
|
-
instance_family: str = typer.Option(
|
|
111
|
-
...,
|
|
112
|
-
"--family",
|
|
113
|
-
help="Name of the instance family. For more information about instance families, refer to the SQL CREATE COMPUTE POOL command.",
|
|
114
|
-
show_default=False,
|
|
115
|
-
),
|
|
116
|
-
min_nodes: int = MinNodesOption(),
|
|
117
|
-
max_nodes: Optional[int] = MaxNodesOption(),
|
|
118
|
-
auto_resume: bool = AutoResumeOption(),
|
|
119
|
-
initially_suspended: bool = typer.Option(
|
|
120
|
-
False,
|
|
121
|
-
"--init-suspend/--no-init-suspend",
|
|
122
|
-
help="Starts the compute pool in a suspended state.",
|
|
123
|
-
),
|
|
124
|
-
auto_suspend_secs: int = AutoSuspendSecsOption(),
|
|
125
|
-
comment: Optional[str] = CommentOption(help=_COMMENT_HELP),
|
|
126
|
-
if_not_exists: bool = IfNotExistsOption(),
|
|
127
|
-
**options,
|
|
128
|
-
) -> CommandResult:
|
|
129
|
-
"""
|
|
130
|
-
Creates a new compute pool.
|
|
131
|
-
"""
|
|
132
|
-
max_nodes = validate_and_set_instances(min_nodes, max_nodes, "nodes")
|
|
133
|
-
cursor = ComputePoolManager().create(
|
|
134
|
-
pool_name=name,
|
|
135
|
-
min_nodes=min_nodes,
|
|
136
|
-
max_nodes=max_nodes,
|
|
137
|
-
instance_family=instance_family,
|
|
138
|
-
auto_resume=auto_resume,
|
|
139
|
-
initially_suspended=initially_suspended,
|
|
140
|
-
auto_suspend_secs=auto_suspend_secs,
|
|
141
|
-
comment=comment,
|
|
142
|
-
if_not_exists=if_not_exists,
|
|
143
|
-
)
|
|
144
|
-
return SingleQueryResult(cursor)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
@app.command("stop-all", requires_connection=True)
|
|
148
|
-
def stop_all(name: str = ComputePoolNameArgument, **options) -> CommandResult:
|
|
149
|
-
"""
|
|
150
|
-
Deletes all services running on the compute pool.
|
|
151
|
-
"""
|
|
152
|
-
cursor = ComputePoolManager().stop(pool_name=name)
|
|
153
|
-
return SingleQueryResult(cursor)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
@app.command(requires_connection=True)
|
|
157
|
-
def suspend(name: str = ComputePoolNameArgument, **options) -> CommandResult:
|
|
158
|
-
"""
|
|
159
|
-
Suspends the compute pool by suspending all currently running services and then releasing compute pool nodes.
|
|
160
|
-
"""
|
|
161
|
-
return SingleQueryResult(ComputePoolManager().suspend(name))
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@app.command(requires_connection=True)
|
|
165
|
-
def resume(name: str = ComputePoolNameArgument, **options) -> CommandResult:
|
|
166
|
-
"""
|
|
167
|
-
Resumes the compute pool from a SUSPENDED state.
|
|
168
|
-
"""
|
|
169
|
-
return SingleQueryResult(ComputePoolManager().resume(name))
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
@app.command("set", requires_connection=True)
|
|
173
|
-
def set_property(
|
|
174
|
-
name: str = ComputePoolNameArgument,
|
|
175
|
-
min_nodes: Optional[int] = MinNodesOption(default=None, show_default=False),
|
|
176
|
-
max_nodes: Optional[int] = MaxNodesOption(show_default=False),
|
|
177
|
-
auto_resume: Optional[bool] = AutoResumeOption(default=None, show_default=False),
|
|
178
|
-
auto_suspend_secs: Optional[int] = AutoSuspendSecsOption(
|
|
179
|
-
default=None, show_default=False
|
|
180
|
-
),
|
|
181
|
-
comment: Optional[str] = CommentOption(
|
|
182
|
-
help="Comment for the compute pool.", show_default=False
|
|
183
|
-
),
|
|
184
|
-
**options,
|
|
185
|
-
) -> CommandResult:
|
|
186
|
-
"""
|
|
187
|
-
Sets one or more properties for the compute pool.
|
|
188
|
-
"""
|
|
189
|
-
cursor = ComputePoolManager().set_property(
|
|
190
|
-
pool_name=name,
|
|
191
|
-
min_nodes=min_nodes,
|
|
192
|
-
max_nodes=max_nodes,
|
|
193
|
-
auto_resume=auto_resume,
|
|
194
|
-
auto_suspend_secs=auto_suspend_secs,
|
|
195
|
-
comment=comment,
|
|
196
|
-
)
|
|
197
|
-
return SingleQueryResult(cursor)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
@app.command("unset", requires_connection=True)
|
|
201
|
-
def unset_property(
|
|
202
|
-
name: str = ComputePoolNameArgument,
|
|
203
|
-
auto_resume: bool = AutoResumeOption(
|
|
204
|
-
default=False,
|
|
205
|
-
param_decls=["--auto-resume"],
|
|
206
|
-
help=f"Reset the AUTO_RESUME property - {_AUTO_RESUME_HELP}",
|
|
207
|
-
show_default=False,
|
|
208
|
-
),
|
|
209
|
-
auto_suspend_secs: bool = AutoSuspendSecsOption(
|
|
210
|
-
default=False,
|
|
211
|
-
help=f"Reset the AUTO_SUSPEND_SECS property - {_AUTO_SUSPEND_SECS_HELP}",
|
|
212
|
-
show_default=False,
|
|
213
|
-
),
|
|
214
|
-
comment: bool = CommentOption(
|
|
215
|
-
default=False,
|
|
216
|
-
help=f"Reset the COMMENT property - {_COMMENT_HELP}",
|
|
217
|
-
callback=None,
|
|
218
|
-
show_default=False,
|
|
219
|
-
),
|
|
220
|
-
**options,
|
|
221
|
-
) -> CommandResult:
|
|
222
|
-
"""
|
|
223
|
-
Resets one or more properties for the compute pool to their default value(s).
|
|
224
|
-
"""
|
|
225
|
-
cursor = ComputePoolManager().unset_property(
|
|
226
|
-
pool_name=name,
|
|
227
|
-
auto_resume=auto_resume,
|
|
228
|
-
auto_suspend_secs=auto_suspend_secs,
|
|
229
|
-
comment=comment,
|
|
230
|
-
)
|
|
231
|
-
return SingleQueryResult(cursor)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
@app.command(requires_connection=True)
|
|
235
|
-
def status(pool_name: str = ComputePoolNameArgument, **options) -> CommandResult:
|
|
236
|
-
"""
|
|
237
|
-
Retrieves the status of a compute pool along with a relevant message, if one exists.
|
|
238
|
-
"""
|
|
239
|
-
cursor = ComputePoolManager().status(pool_name=pool_name)
|
|
240
|
-
return SingleQueryResult(cursor)
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
from typing import List, Optional
|
|
18
|
-
|
|
19
|
-
from snowflake.cli.api.constants import ObjectType
|
|
20
|
-
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
21
|
-
from snowflake.cli.plugins.spcs.common import (
|
|
22
|
-
NoPropertiesProvidedError,
|
|
23
|
-
handle_object_already_exists,
|
|
24
|
-
strip_empty_lines,
|
|
25
|
-
)
|
|
26
|
-
from snowflake.connector.cursor import SnowflakeCursor
|
|
27
|
-
from snowflake.connector.errors import ProgrammingError
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ComputePoolManager(SqlExecutionMixin):
|
|
31
|
-
def create(
|
|
32
|
-
self,
|
|
33
|
-
pool_name: str,
|
|
34
|
-
min_nodes: int,
|
|
35
|
-
max_nodes: int,
|
|
36
|
-
instance_family: str,
|
|
37
|
-
auto_resume: bool,
|
|
38
|
-
initially_suspended: bool,
|
|
39
|
-
auto_suspend_secs: int,
|
|
40
|
-
comment: Optional[str],
|
|
41
|
-
if_not_exists: bool,
|
|
42
|
-
) -> SnowflakeCursor:
|
|
43
|
-
create_statement = "CREATE COMPUTE POOL"
|
|
44
|
-
if if_not_exists:
|
|
45
|
-
create_statement = f"{create_statement} IF NOT EXISTS"
|
|
46
|
-
query = f"""\
|
|
47
|
-
{create_statement} {pool_name}
|
|
48
|
-
MIN_NODES = {min_nodes}
|
|
49
|
-
MAX_NODES = {max_nodes}
|
|
50
|
-
INSTANCE_FAMILY = {instance_family}
|
|
51
|
-
AUTO_RESUME = {auto_resume}
|
|
52
|
-
INITIALLY_SUSPENDED = {initially_suspended}
|
|
53
|
-
AUTO_SUSPEND_SECS = {auto_suspend_secs}
|
|
54
|
-
""".splitlines()
|
|
55
|
-
if comment:
|
|
56
|
-
query.append(f"COMMENT = {comment}")
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
return self._execute_query(strip_empty_lines(query))
|
|
60
|
-
except ProgrammingError as e:
|
|
61
|
-
handle_object_already_exists(e, ObjectType.COMPUTE_POOL, pool_name)
|
|
62
|
-
|
|
63
|
-
def stop(self, pool_name: str) -> SnowflakeCursor:
|
|
64
|
-
return self._execute_query(f"alter compute pool {pool_name} stop all")
|
|
65
|
-
|
|
66
|
-
def suspend(self, pool_name: str) -> SnowflakeCursor:
|
|
67
|
-
return self._execute_query(f"alter compute pool {pool_name} suspend")
|
|
68
|
-
|
|
69
|
-
def resume(self, pool_name: str) -> SnowflakeCursor:
|
|
70
|
-
return self._execute_query(f"alter compute pool {pool_name} resume")
|
|
71
|
-
|
|
72
|
-
def set_property(
|
|
73
|
-
self,
|
|
74
|
-
pool_name: str,
|
|
75
|
-
min_nodes: Optional[int],
|
|
76
|
-
max_nodes: Optional[int],
|
|
77
|
-
auto_resume: Optional[bool],
|
|
78
|
-
auto_suspend_secs: Optional[int],
|
|
79
|
-
comment: Optional[str],
|
|
80
|
-
) -> SnowflakeCursor:
|
|
81
|
-
property_pairs = [
|
|
82
|
-
("min_nodes", min_nodes),
|
|
83
|
-
("max_nodes", max_nodes),
|
|
84
|
-
("auto_resume", auto_resume),
|
|
85
|
-
("auto_suspend_secs", auto_suspend_secs),
|
|
86
|
-
("comment", comment),
|
|
87
|
-
]
|
|
88
|
-
|
|
89
|
-
# Check if all provided properties are set to None (no properties are being set)
|
|
90
|
-
if all([value is None for property_name, value in property_pairs]):
|
|
91
|
-
raise NoPropertiesProvidedError(
|
|
92
|
-
f"No properties specified for compute pool '{pool_name}'. Please provide at least one property to set."
|
|
93
|
-
)
|
|
94
|
-
query: List[str] = [f"alter compute pool {pool_name} set"]
|
|
95
|
-
for property_name, value in property_pairs:
|
|
96
|
-
if value is not None:
|
|
97
|
-
query.append(f"{property_name} = {value}")
|
|
98
|
-
return self._execute_query(strip_empty_lines(query))
|
|
99
|
-
|
|
100
|
-
def unset_property(
|
|
101
|
-
self, pool_name: str, auto_resume: bool, auto_suspend_secs: bool, comment: bool
|
|
102
|
-
):
|
|
103
|
-
property_pairs = [
|
|
104
|
-
("auto_resume", auto_resume),
|
|
105
|
-
("auto_suspend_secs", auto_suspend_secs),
|
|
106
|
-
("comment", comment),
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
# Check if all properties provided are False (no properties are being unset)
|
|
110
|
-
if not any([value for property_name, value in property_pairs]):
|
|
111
|
-
raise NoPropertiesProvidedError(
|
|
112
|
-
f"No properties specified for compute pool '{pool_name}'. Please provide at least one property to reset to its default value."
|
|
113
|
-
)
|
|
114
|
-
unset_list = [property_name for property_name, value in property_pairs if value]
|
|
115
|
-
query = f"alter compute pool {pool_name} unset {','.join(unset_list)}"
|
|
116
|
-
return self._execute_query(query)
|
|
117
|
-
|
|
118
|
-
def status(self, pool_name: str):
|
|
119
|
-
return self._execute_query(
|
|
120
|
-
f"call system$get_compute_pool_status('{pool_name}')"
|
|
121
|
-
)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
16
|
-
from snowflake.cli.api.output.types import MessageResult, ObjectResult
|
|
17
|
-
from snowflake.cli.plugins.spcs.image_registry.manager import (
|
|
18
|
-
RegistryManager,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
app = SnowTyperFactory(
|
|
22
|
-
name="image-registry",
|
|
23
|
-
help="Manages Snowpark Container Services image registries.",
|
|
24
|
-
short_help="Manages image registries.",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
_TOKEN_EPILOG = """\
|
|
29
|
-
Usage Example: snow spcs image-registry token --format JSON | docker login $(snow spcs image-registry url) -u 0sessiontoken --password-stdin
|
|
30
|
-
|
|
31
|
-
See the following for how to use this command to authenticate with SSO:
|
|
32
|
-
https://community.snowflake.com/s/article/Authenticating-with-Snowpark-Container-Services-Image-Repository-via-SSO-and-Token-with-Snow-CLI\
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@app.command(requires_connection=True, epilog=_TOKEN_EPILOG)
|
|
37
|
-
def token(**options) -> ObjectResult:
|
|
38
|
-
"""
|
|
39
|
-
Retrieves a registry authentication token based on your current connection.
|
|
40
|
-
|
|
41
|
-
Note that this token is specific to your current user and will not grant access to any repositories that your current user cannot access.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"""
|
|
45
|
-
return ObjectResult(RegistryManager().get_token())
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@app.command(requires_connection=True)
|
|
49
|
-
def url(**options) -> MessageResult:
|
|
50
|
-
"""
|
|
51
|
-
Gets the image registry URL for the current account.
|
|
52
|
-
|
|
53
|
-
Must be called from a role that can view at least one image repository in the image registry.
|
|
54
|
-
"""
|
|
55
|
-
return MessageResult(RegistryManager().get_registry_url())
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@app.command(requires_connection=True)
|
|
59
|
-
def login(**options) -> MessageResult:
|
|
60
|
-
"""
|
|
61
|
-
Logs in to the account image registry with the current user's credentials through Docker.
|
|
62
|
-
|
|
63
|
-
Must be called from a role that can view at least one image repository in the image registry.
|
|
64
|
-
"""
|
|
65
|
-
return MessageResult(RegistryManager().docker_registry_login().strip())
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
import base64
|
|
16
|
-
import json
|
|
17
|
-
import re
|
|
18
|
-
import subprocess
|
|
19
|
-
from urllib.parse import urlparse
|
|
20
|
-
|
|
21
|
-
import requests
|
|
22
|
-
from click import ClickException
|
|
23
|
-
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
24
|
-
from snowflake.connector.cursor import DictCursor
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class NoImageRepositoriesFoundError(ClickException):
|
|
28
|
-
def __init__(self):
|
|
29
|
-
super().__init__(
|
|
30
|
-
f"No image repository found. To run this command, please switch to a role with read access to at least one image repository or create a new image repository first."
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class RegistryManager(SqlExecutionMixin):
|
|
35
|
-
def get_token(self):
|
|
36
|
-
"""
|
|
37
|
-
Get token to authenticate with registry.
|
|
38
|
-
"""
|
|
39
|
-
self._execute_query(
|
|
40
|
-
"alter session set PYTHON_CONNECTOR_QUERY_RESULT_FORMAT = 'json'"
|
|
41
|
-
).fetchall()
|
|
42
|
-
# disable session deletion
|
|
43
|
-
self._conn._all_async_queries_finished = lambda: False # noqa: SLF001
|
|
44
|
-
if self._conn._rest is None: # noqa: SLF001
|
|
45
|
-
raise Exception("Failed to connect to Snowflake to retrieve token.")
|
|
46
|
-
# obtain and create the token
|
|
47
|
-
token_data = self._conn._rest._token_request("ISSUE") # noqa: SLF001
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
"token": token_data["data"]["sessionToken"],
|
|
51
|
-
"expires_in": token_data["data"]["validityInSecondsST"],
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
def login_to_registry(self, repo_url):
|
|
55
|
-
"""
|
|
56
|
-
Logs in to the registry using basic authentication and generates a bearer authentication token.
|
|
57
|
-
"""
|
|
58
|
-
token = json.dumps(self.get_token())
|
|
59
|
-
parsed_url = urlparse(repo_url)
|
|
60
|
-
|
|
61
|
-
scheme = parsed_url.scheme
|
|
62
|
-
host = parsed_url.netloc
|
|
63
|
-
|
|
64
|
-
login_url = f"{scheme}://{host}/login"
|
|
65
|
-
creds = base64.b64encode(f"0sessiontoken:{token}".encode("utf-8"))
|
|
66
|
-
creds = creds.decode("utf-8")
|
|
67
|
-
resp = requests.get(login_url, headers={"Authorization": f"Basic {creds}"})
|
|
68
|
-
|
|
69
|
-
if resp.status_code != 200:
|
|
70
|
-
raise ClickException(f"Failed to login to the repository {resp.text}")
|
|
71
|
-
return json.loads(resp.text)["token"]
|
|
72
|
-
|
|
73
|
-
def _has_url_scheme(self, url: str):
|
|
74
|
-
return re.fullmatch(r"^.*//.+", url) is not None
|
|
75
|
-
|
|
76
|
-
def get_registry_url(self) -> str:
|
|
77
|
-
repositories_query = "show image repositories in account"
|
|
78
|
-
result_set = self._execute_query(repositories_query, cursor_class=DictCursor)
|
|
79
|
-
results = result_set.fetchall()
|
|
80
|
-
if len(results) == 0:
|
|
81
|
-
raise NoImageRepositoriesFoundError()
|
|
82
|
-
sample_repository_url = results[0]["repository_url"]
|
|
83
|
-
if not self._has_url_scheme(sample_repository_url):
|
|
84
|
-
sample_repository_url = f"//{sample_repository_url}"
|
|
85
|
-
return urlparse(sample_repository_url).netloc
|
|
86
|
-
|
|
87
|
-
def docker_registry_login(self) -> str:
|
|
88
|
-
registry_url = self.get_registry_url()
|
|
89
|
-
token = self.get_token()
|
|
90
|
-
command = [
|
|
91
|
-
"docker",
|
|
92
|
-
"login",
|
|
93
|
-
"--username",
|
|
94
|
-
"0sessiontoken",
|
|
95
|
-
"--password-stdin",
|
|
96
|
-
registry_url,
|
|
97
|
-
]
|
|
98
|
-
try:
|
|
99
|
-
return subprocess.check_output(
|
|
100
|
-
command, input=json.dumps(token), text=True, stderr=subprocess.PIPE
|
|
101
|
-
)
|
|
102
|
-
except subprocess.CalledProcessError as e:
|
|
103
|
-
raise ClickException(f"Login Failed: {e.stderr}".strip())
|
|
104
|
-
except FileNotFoundError:
|
|
105
|
-
raise ClickException("Docker is not installed.")
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|