snowflake-cli 3.2.2__py3-none-any.whl → 3.4.1__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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/_app/__main__.py +2 -2
- snowflake/cli/_app/cli_app.py +224 -192
- snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +1 -27
- snowflake/cli/_app/constants.py +4 -0
- snowflake/cli/_app/snow_connector.py +12 -0
- snowflake/cli/_app/telemetry.py +10 -3
- snowflake/cli/_plugins/connection/util.py +12 -19
- snowflake/cli/_plugins/cortex/commands.py +2 -4
- snowflake/cli/_plugins/git/manager.py +1 -1
- snowflake/cli/_plugins/helpers/commands.py +207 -1
- snowflake/cli/_plugins/nativeapp/artifacts.py +16 -628
- snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +42 -20
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +9 -2
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -3
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +44 -34
- snowflake/cli/_plugins/nativeapp/commands.py +113 -21
- snowflake/cli/_plugins/nativeapp/constants.py +5 -0
- snowflake/cli/_plugins/nativeapp/entities/application.py +226 -296
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +911 -141
- snowflake/cli/_plugins/nativeapp/entities/application_package_child_interface.py +43 -0
- snowflake/cli/_plugins/nativeapp/feature_flags.py +5 -1
- snowflake/cli/_plugins/nativeapp/release_channel/__init__.py +13 -0
- snowflake/cli/_plugins/nativeapp/release_channel/commands.py +246 -0
- snowflake/cli/_plugins/nativeapp/release_directive/__init__.py +13 -0
- snowflake/cli/_plugins/nativeapp/release_directive/commands.py +243 -0
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +9 -17
- snowflake/cli/_plugins/nativeapp/sf_facade_exceptions.py +80 -0
- snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +1184 -80
- snowflake/cli/_plugins/nativeapp/utils.py +11 -0
- snowflake/cli/_plugins/nativeapp/v2_conversions/compat.py +7 -3
- snowflake/cli/_plugins/nativeapp/version/commands.py +32 -5
- snowflake/cli/_plugins/notebook/commands.py +55 -2
- snowflake/cli/_plugins/notebook/exceptions.py +1 -1
- snowflake/cli/_plugins/notebook/manager.py +7 -5
- snowflake/cli/_plugins/notebook/notebook_entity.py +120 -0
- snowflake/cli/_plugins/notebook/notebook_entity_model.py +42 -0
- snowflake/cli/_plugins/notebook/notebook_project_paths.py +15 -0
- snowflake/cli/_plugins/notebook/types.py +3 -0
- snowflake/cli/_plugins/snowpark/commands.py +48 -30
- snowflake/cli/_plugins/snowpark/common.py +47 -2
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +247 -4
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +18 -30
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +156 -23
- snowflake/cli/_plugins/snowpark/zipper.py +33 -1
- snowflake/cli/_plugins/spcs/common.py +129 -0
- snowflake/cli/_plugins/spcs/services/commands.py +131 -14
- snowflake/cli/_plugins/spcs/services/manager.py +169 -1
- snowflake/cli/_plugins/stage/commands.py +2 -1
- snowflake/cli/_plugins/stage/diff.py +60 -39
- snowflake/cli/_plugins/stage/manager.py +34 -13
- snowflake/cli/_plugins/stage/utils.py +1 -1
- snowflake/cli/_plugins/streamlit/commands.py +10 -1
- snowflake/cli/_plugins/streamlit/manager.py +70 -22
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +131 -1
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +14 -24
- snowflake/cli/_plugins/streamlit/streamlit_project_paths.py +30 -0
- snowflake/cli/_plugins/workspace/commands.py +6 -5
- snowflake/cli/_plugins/workspace/manager.py +9 -5
- snowflake/cli/api/artifacts/__init__.py +13 -0
- snowflake/cli/api/artifacts/bundle_map.py +500 -0
- snowflake/cli/api/artifacts/common.py +78 -0
- snowflake/cli/api/artifacts/utils.py +82 -0
- snowflake/cli/api/cli_global_context.py +36 -2
- snowflake/cli/api/commands/flags.py +10 -4
- snowflake/cli/api/commands/utils.py +28 -2
- snowflake/cli/api/config.py +6 -2
- snowflake/cli/api/connections.py +12 -1
- snowflake/cli/api/constants.py +10 -1
- snowflake/cli/api/entities/common.py +81 -14
- snowflake/cli/api/entities/resolver.py +160 -0
- snowflake/cli/api/entities/utils.py +65 -23
- snowflake/cli/api/errno.py +63 -3
- snowflake/cli/api/feature_flags.py +19 -4
- snowflake/cli/api/metrics.py +21 -27
- snowflake/cli/api/project/definition_conversion.py +4 -4
- snowflake/cli/api/project/project_paths.py +28 -0
- snowflake/cli/api/project/schemas/entities/common.py +130 -1
- snowflake/cli/api/project/schemas/entities/entities.py +4 -0
- snowflake/cli/api/project/schemas/project_definition.py +54 -6
- snowflake/cli/api/project/schemas/updatable_model.py +2 -2
- snowflake/cli/api/project/schemas/v1/native_app/native_app.py +5 -7
- snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +1 -1
- snowflake/cli/api/project/util.py +45 -0
- snowflake/cli/api/secure_path.py +6 -0
- snowflake/cli/api/sql_execution.py +5 -1
- snowflake/cli/api/stage_path.py +7 -2
- snowflake/cli/api/utils/graph.py +3 -0
- snowflake/cli/api/utils/path_utils.py +24 -0
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/METADATA +14 -15
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/RECORD +96 -82
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/WHEEL +1 -1
- snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -13,7 +13,6 @@ from click import ClickException, UsageError
|
|
|
13
13
|
from pydantic import Field, field_validator
|
|
14
14
|
from snowflake.cli._plugins.connection.util import (
|
|
15
15
|
UIParameter,
|
|
16
|
-
get_ui_parameter,
|
|
17
16
|
make_snowsight_url,
|
|
18
17
|
)
|
|
19
18
|
from snowflake.cli._plugins.nativeapp.artifacts import (
|
|
@@ -26,11 +25,8 @@ from snowflake.cli._plugins.nativeapp.common_flags import (
|
|
|
26
25
|
)
|
|
27
26
|
from snowflake.cli._plugins.nativeapp.constants import (
|
|
28
27
|
ALLOWED_SPECIAL_COMMENTS,
|
|
29
|
-
AUTHORIZE_TELEMETRY_COL,
|
|
30
28
|
COMMENT_COL,
|
|
31
|
-
NAME_COL,
|
|
32
29
|
OWNER_COL,
|
|
33
|
-
SPECIAL_COMMENT,
|
|
34
30
|
)
|
|
35
31
|
from snowflake.cli._plugins.nativeapp.entities.application_package import (
|
|
36
32
|
ApplicationPackageEntity,
|
|
@@ -53,27 +49,30 @@ from snowflake.cli._plugins.nativeapp.same_account_install_method import (
|
|
|
53
49
|
SameAccountInstallMethod,
|
|
54
50
|
)
|
|
55
51
|
from snowflake.cli._plugins.nativeapp.sf_facade import get_snowflake_facade
|
|
52
|
+
from snowflake.cli._plugins.nativeapp.sf_facade_exceptions import (
|
|
53
|
+
UpgradeApplicationRestrictionError,
|
|
54
|
+
)
|
|
56
55
|
from snowflake.cli._plugins.nativeapp.utils import needs_confirmation
|
|
56
|
+
from snowflake.cli._plugins.stage.manager import DefaultStagePathParts
|
|
57
57
|
from snowflake.cli._plugins.workspace.context import ActionContext
|
|
58
|
-
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
58
|
+
from snowflake.cli.api.cli_global_context import get_cli_context, span
|
|
59
59
|
from snowflake.cli.api.console.abc import AbstractConsole
|
|
60
|
-
from snowflake.cli.api.
|
|
60
|
+
from snowflake.cli.api.constants import ObjectType
|
|
61
|
+
from snowflake.cli.api.entities.common import (
|
|
62
|
+
EntityBase,
|
|
63
|
+
attach_spans_to_entity_actions,
|
|
64
|
+
)
|
|
61
65
|
from snowflake.cli.api.entities.utils import (
|
|
62
66
|
drop_generic_object,
|
|
63
67
|
execute_post_deploy_hooks,
|
|
64
68
|
generic_sql_error_handler,
|
|
69
|
+
get_sql_executor,
|
|
65
70
|
print_messages,
|
|
66
71
|
)
|
|
67
72
|
from snowflake.cli.api.errno import (
|
|
68
73
|
APPLICATION_NO_LONGER_AVAILABLE,
|
|
69
74
|
APPLICATION_OWNS_EXTERNAL_OBJECTS,
|
|
70
|
-
APPLICATION_REQUIRES_TELEMETRY_SHARING,
|
|
71
|
-
CANNOT_DISABLE_MANDATORY_TELEMETRY,
|
|
72
|
-
CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
|
|
73
|
-
CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
|
|
74
75
|
DOES_NOT_EXIST_OR_NOT_AUTHORIZED,
|
|
75
|
-
NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
76
|
-
ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
77
76
|
)
|
|
78
77
|
from snowflake.cli.api.metrics import CLICounterField
|
|
79
78
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
@@ -85,7 +84,6 @@ from snowflake.cli.api.project.schemas.entities.common import (
|
|
|
85
84
|
from snowflake.cli.api.project.schemas.updatable_model import DiscriminatorField
|
|
86
85
|
from snowflake.cli.api.project.util import (
|
|
87
86
|
append_test_resource_suffix,
|
|
88
|
-
extract_schema,
|
|
89
87
|
identifier_for_url,
|
|
90
88
|
to_identifier,
|
|
91
89
|
unquote_identifier,
|
|
@@ -94,15 +92,6 @@ from snowflake.connector import DictCursor, ProgrammingError
|
|
|
94
92
|
|
|
95
93
|
log = logging.getLogger(__name__)
|
|
96
94
|
|
|
97
|
-
# Reasons why an `alter application ... upgrade` might fail
|
|
98
|
-
UPGRADE_RESTRICTION_CODES = {
|
|
99
|
-
CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
|
|
100
|
-
CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
|
|
101
|
-
ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
102
|
-
NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
103
|
-
APPLICATION_NO_LONGER_AVAILABLE,
|
|
104
|
-
}
|
|
105
|
-
|
|
106
95
|
ApplicationOwnedObject = TypedDict("ApplicationOwnedObject", {"name": str, "type": str})
|
|
107
96
|
|
|
108
97
|
|
|
@@ -134,18 +123,12 @@ class EventSharingHandler:
|
|
|
134
123
|
self._is_dev_mode = install_method.is_dev_mode
|
|
135
124
|
self._metrics = get_cli_context().metrics
|
|
136
125
|
self._console = console
|
|
137
|
-
|
|
138
|
-
self._event_sharing_enabled = (
|
|
139
|
-
|
|
140
|
-
connection, UIParameter.NA_EVENT_SHARING_V2, "true"
|
|
141
|
-
).lower()
|
|
142
|
-
== "true"
|
|
126
|
+
|
|
127
|
+
self._event_sharing_enabled = get_snowflake_facade().get_ui_parameter(
|
|
128
|
+
UIParameter.NA_EVENT_SHARING_V2, True
|
|
143
129
|
)
|
|
144
|
-
self._event_sharing_enforced = (
|
|
145
|
-
|
|
146
|
-
connection, UIParameter.NA_ENFORCE_MANDATORY_FILTERS, "true"
|
|
147
|
-
).lower()
|
|
148
|
-
== "true"
|
|
130
|
+
self._event_sharing_enforced = get_snowflake_facade().get_ui_parameter(
|
|
131
|
+
UIParameter.NA_ENFORCE_MANDATORY_FILTERS, True
|
|
149
132
|
)
|
|
150
133
|
|
|
151
134
|
self._share_mandatory_events = (
|
|
@@ -187,31 +170,11 @@ class EventSharingHandler:
|
|
|
187
170
|
def _contains_mandatory_events(self, events_definitions: List[Dict[str, str]]):
|
|
188
171
|
return any(event["sharing"] == "MANDATORY" for event in events_definitions)
|
|
189
172
|
|
|
190
|
-
def
|
|
191
|
-
self,
|
|
192
|
-
) -> Optional[bool]:
|
|
193
|
-
"""
|
|
194
|
-
Determines whether event sharing should be authorized during the creation of the application object.
|
|
195
|
-
|
|
196
|
-
Outputs:
|
|
197
|
-
- None: Event sharing should not be updated or explicitly set.
|
|
198
|
-
- True: Event sharing should be authorized.
|
|
199
|
-
- False: Event sharing should be disabled.
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
if not self._event_sharing_enabled:
|
|
203
|
-
return None
|
|
204
|
-
|
|
205
|
-
return self._share_mandatory_events
|
|
206
|
-
|
|
207
|
-
def should_authorize_event_sharing_after_upgrade(
|
|
173
|
+
def should_authorize_event_sharing(
|
|
208
174
|
self,
|
|
209
|
-
upgraded_app_properties: Dict[str, str],
|
|
210
175
|
) -> Optional[bool]:
|
|
211
176
|
"""
|
|
212
|
-
Determines whether event sharing should be authorized
|
|
213
|
-
|
|
214
|
-
:param upgraded_app_properties: The properties of the application after upgrading.
|
|
177
|
+
Determines whether event sharing should be authorized.
|
|
215
178
|
|
|
216
179
|
Outputs:
|
|
217
180
|
- None: Event sharing should not be updated or explicitly set.
|
|
@@ -222,15 +185,6 @@ class EventSharingHandler:
|
|
|
222
185
|
if not self._event_sharing_enabled:
|
|
223
186
|
return None
|
|
224
187
|
|
|
225
|
-
current_app_authorization = (
|
|
226
|
-
upgraded_app_properties.get(AUTHORIZE_TELEMETRY_COL, "false").lower()
|
|
227
|
-
== "true"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
# Skip the update if the current value is the same as the one we want to set
|
|
231
|
-
if current_app_authorization == self._share_mandatory_events:
|
|
232
|
-
return None
|
|
233
|
-
|
|
234
188
|
return self._share_mandatory_events
|
|
235
189
|
|
|
236
190
|
def event_sharing_warning(self, message: str):
|
|
@@ -321,6 +275,7 @@ class ApplicationEntityModel(EntityModelBase):
|
|
|
321
275
|
return with_suffix
|
|
322
276
|
|
|
323
277
|
|
|
278
|
+
@attach_spans_to_entity_actions(entity_name="app")
|
|
324
279
|
class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
325
280
|
"""
|
|
326
281
|
A Native App application object, created from an application package.
|
|
@@ -355,6 +310,18 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
355
310
|
model = self._entity_model
|
|
356
311
|
return model.meta and model.meta.post_deploy
|
|
357
312
|
|
|
313
|
+
@property
|
|
314
|
+
def console(self) -> AbstractConsole:
|
|
315
|
+
return self._workspace_ctx.console
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def debug(self) -> bool | None:
|
|
319
|
+
return self._entity_model.debug
|
|
320
|
+
|
|
321
|
+
@property
|
|
322
|
+
def telemetry(self) -> EventSharingTelemetry | None:
|
|
323
|
+
return self._entity_model.telemetry
|
|
324
|
+
|
|
358
325
|
def action_deploy(
|
|
359
326
|
self,
|
|
360
327
|
action_ctx: ActionContext,
|
|
@@ -362,8 +329,8 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
362
329
|
prune: bool,
|
|
363
330
|
recursive: bool,
|
|
364
331
|
paths: List[Path],
|
|
332
|
+
release_channel: Optional[str] = None,
|
|
365
333
|
validate: bool = ValidateOption,
|
|
366
|
-
stage_fqn: Optional[str] = None,
|
|
367
334
|
interactive: bool = InteractiveOption,
|
|
368
335
|
version: Optional[str] = None,
|
|
369
336
|
patch: Optional[int] = None,
|
|
@@ -378,7 +345,8 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
378
345
|
package_entity: ApplicationPackageEntity = action_ctx.get_entity(
|
|
379
346
|
self.package_entity_id
|
|
380
347
|
)
|
|
381
|
-
|
|
348
|
+
|
|
349
|
+
stage_path = package_entity.stage_path
|
|
382
350
|
|
|
383
351
|
if force:
|
|
384
352
|
policy = AllowAlwaysPolicy()
|
|
@@ -389,15 +357,25 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
389
357
|
|
|
390
358
|
# same-account release directive
|
|
391
359
|
if from_release_directive:
|
|
360
|
+
release_channel = package_entity.get_sanitized_release_channel(
|
|
361
|
+
release_channel
|
|
362
|
+
)
|
|
363
|
+
|
|
392
364
|
self.create_or_upgrade_app(
|
|
393
365
|
package=package_entity,
|
|
394
|
-
|
|
366
|
+
stage_path=stage_path,
|
|
395
367
|
install_method=SameAccountInstallMethod.release_directive(),
|
|
368
|
+
release_channel=release_channel,
|
|
396
369
|
policy=policy,
|
|
397
370
|
interactive=interactive,
|
|
398
371
|
)
|
|
399
372
|
return
|
|
400
373
|
|
|
374
|
+
if release_channel:
|
|
375
|
+
raise UsageError(
|
|
376
|
+
f"Release channel is only supported when --from-release-directive is used."
|
|
377
|
+
)
|
|
378
|
+
|
|
401
379
|
# versioned dev
|
|
402
380
|
if version:
|
|
403
381
|
try:
|
|
@@ -413,7 +391,7 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
413
391
|
|
|
414
392
|
self.create_or_upgrade_app(
|
|
415
393
|
package=package_entity,
|
|
416
|
-
|
|
394
|
+
stage_path=stage_path,
|
|
417
395
|
install_method=SameAccountInstallMethod.versioned_dev(version, patch),
|
|
418
396
|
policy=policy,
|
|
419
397
|
interactive=interactive,
|
|
@@ -427,13 +405,12 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
427
405
|
recursive=True,
|
|
428
406
|
paths=[],
|
|
429
407
|
validate=validate,
|
|
430
|
-
stage_fqn=stage_fqn,
|
|
431
408
|
interactive=interactive,
|
|
432
409
|
force=force,
|
|
433
410
|
)
|
|
434
411
|
self.create_or_upgrade_app(
|
|
435
412
|
package=package_entity,
|
|
436
|
-
|
|
413
|
+
stage_path=stage_path,
|
|
437
414
|
install_method=SameAccountInstallMethod.unversioned_dev(),
|
|
438
415
|
policy=policy,
|
|
439
416
|
interactive=interactive,
|
|
@@ -451,14 +428,14 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
451
428
|
"""
|
|
452
429
|
Attempts to drop the application object if all validations and user prompts allow so.
|
|
453
430
|
"""
|
|
454
|
-
console = self._workspace_ctx.console
|
|
455
|
-
|
|
456
431
|
needs_confirm = True
|
|
457
432
|
|
|
458
433
|
# 1. If existing application is not found, exit gracefully
|
|
459
|
-
show_obj_row =
|
|
434
|
+
show_obj_row = get_snowflake_facade().get_existing_app_info(
|
|
435
|
+
self.name, self.role
|
|
436
|
+
)
|
|
460
437
|
if show_obj_row is None:
|
|
461
|
-
console.warning(
|
|
438
|
+
self.console.warning(
|
|
462
439
|
f"Role {self.role} does not own any application object with the name {self.name}, or the application object does not exist."
|
|
463
440
|
)
|
|
464
441
|
return
|
|
@@ -485,7 +462,7 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
485
462
|
)
|
|
486
463
|
)
|
|
487
464
|
if not should_drop_object:
|
|
488
|
-
console.message(f"Did not drop application object {self.name}.")
|
|
465
|
+
self.console.message(f"Did not drop application object {self.name}.")
|
|
489
466
|
# The user desires to keep the app, therefore we can't proceed since it would
|
|
490
467
|
# leave behind an orphan app when we get to dropping the package
|
|
491
468
|
raise typer.Abort()
|
|
@@ -524,22 +501,22 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
524
501
|
if has_objects_to_drop:
|
|
525
502
|
if cascade is True:
|
|
526
503
|
# If the user explicitly passed the --cascade flag
|
|
527
|
-
console.message(cascade_true_message)
|
|
528
|
-
with console.indented():
|
|
504
|
+
self.console.message(cascade_true_message)
|
|
505
|
+
with self.console.indented():
|
|
529
506
|
for obj in application_objects:
|
|
530
|
-
console.message(_application_object_to_str(obj))
|
|
507
|
+
self.console.message(_application_object_to_str(obj))
|
|
531
508
|
elif cascade is False:
|
|
532
509
|
# If the user explicitly passed the --no-cascade flag
|
|
533
|
-
console.message(cascade_false_message)
|
|
534
|
-
with console.indented():
|
|
510
|
+
self.console.message(cascade_false_message)
|
|
511
|
+
with self.console.indented():
|
|
535
512
|
for obj in application_objects:
|
|
536
|
-
console.message(_application_object_to_str(obj))
|
|
513
|
+
self.console.message(_application_object_to_str(obj))
|
|
537
514
|
elif interactive:
|
|
538
515
|
# If the user didn't pass any cascade flag and the session is interactive
|
|
539
|
-
console.message(message_prefix)
|
|
540
|
-
with console.indented():
|
|
516
|
+
self.console.message(message_prefix)
|
|
517
|
+
with self.console.indented():
|
|
541
518
|
for obj in application_objects:
|
|
542
|
-
console.message(_application_object_to_str(obj))
|
|
519
|
+
self.console.message(_application_object_to_str(obj))
|
|
543
520
|
user_response = typer.prompt(
|
|
544
521
|
interactive_prompt,
|
|
545
522
|
show_default=False,
|
|
@@ -553,11 +530,11 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
553
530
|
raise typer.Abort()
|
|
554
531
|
else:
|
|
555
532
|
# Else abort since we don't know what to do and can't ask the user
|
|
556
|
-
console.message(message_prefix)
|
|
557
|
-
with console.indented():
|
|
533
|
+
self.console.message(message_prefix)
|
|
534
|
+
with self.console.indented():
|
|
558
535
|
for obj in application_objects:
|
|
559
|
-
console.message(_application_object_to_str(obj))
|
|
560
|
-
console.message(non_interactive_abort)
|
|
536
|
+
self.console.message(_application_object_to_str(obj))
|
|
537
|
+
self.console.message(non_interactive_abort)
|
|
561
538
|
raise typer.Abort()
|
|
562
539
|
elif cascade is None:
|
|
563
540
|
# If there's nothing to drop, set cascade to an explicit False value
|
|
@@ -565,7 +542,7 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
565
542
|
|
|
566
543
|
# 4. All validations have passed, drop object
|
|
567
544
|
drop_generic_object(
|
|
568
|
-
console=console,
|
|
545
|
+
console=self.console,
|
|
569
546
|
object_type="application",
|
|
570
547
|
object_name=self.name,
|
|
571
548
|
role=self.role,
|
|
@@ -629,181 +606,143 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
629
606
|
).fetchall()
|
|
630
607
|
return [{"name": row[1], "type": row[2]} for row in results]
|
|
631
608
|
|
|
632
|
-
def
|
|
609
|
+
def _upgrade_app(
|
|
633
610
|
self,
|
|
634
|
-
|
|
635
|
-
stage_fqn: str,
|
|
611
|
+
stage_path: DefaultStagePathParts,
|
|
636
612
|
install_method: SameAccountInstallMethod,
|
|
613
|
+
event_sharing: EventSharingHandler,
|
|
637
614
|
policy: PolicyBase,
|
|
638
615
|
interactive: bool,
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
console
|
|
642
|
-
debug_mode = model.debug
|
|
616
|
+
release_channel: Optional[str] = None,
|
|
617
|
+
) -> list[tuple[str]] | None:
|
|
618
|
+
self.console.step(f"Upgrading existing application object {self.name}.")
|
|
643
619
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
sql_executor = get_sql_executor()
|
|
648
|
-
with sql_executor.use_role(self.role):
|
|
649
|
-
event_sharing = EventSharingHandler(
|
|
650
|
-
telemetry_definition=model.telemetry,
|
|
651
|
-
deploy_root=package.deploy_root,
|
|
620
|
+
try:
|
|
621
|
+
return get_snowflake_facade().upgrade_application(
|
|
622
|
+
name=self.name,
|
|
652
623
|
install_method=install_method,
|
|
653
|
-
|
|
624
|
+
path_to_version_directory=stage_path.full_path,
|
|
625
|
+
debug_mode=self.debug,
|
|
626
|
+
should_authorize_event_sharing=event_sharing.should_authorize_event_sharing(),
|
|
627
|
+
release_channel=release_channel,
|
|
628
|
+
role=self.role,
|
|
629
|
+
warehouse=self.warehouse,
|
|
654
630
|
)
|
|
631
|
+
except UpgradeApplicationRestrictionError as err:
|
|
632
|
+
self.console.warning(err.message)
|
|
633
|
+
self.drop_application_before_upgrade(policy=policy, interactive=interactive)
|
|
634
|
+
return None
|
|
655
635
|
|
|
656
|
-
|
|
657
|
-
|
|
636
|
+
def _create_app(
|
|
637
|
+
self,
|
|
638
|
+
stage_path: DefaultStagePathParts,
|
|
639
|
+
install_method: SameAccountInstallMethod,
|
|
640
|
+
event_sharing: EventSharingHandler,
|
|
641
|
+
package: ApplicationPackageEntity,
|
|
642
|
+
release_channel: Optional[str] = None,
|
|
643
|
+
) -> list[tuple[str]]:
|
|
644
|
+
self.console.step(f"Creating new application object {self.name} in account.")
|
|
645
|
+
|
|
646
|
+
if package.role != self.role:
|
|
647
|
+
get_snowflake_facade().grant_privileges_to_role(
|
|
648
|
+
privileges=["install", "develop"],
|
|
649
|
+
object_type=ObjectType.APPLICATION_PACKAGE,
|
|
650
|
+
object_identifier=package.name,
|
|
651
|
+
role_to_grant=self.role,
|
|
652
|
+
role_to_use=package.role,
|
|
653
|
+
)
|
|
658
654
|
|
|
659
|
-
|
|
660
|
-
|
|
655
|
+
stage_schema = stage_path.schema
|
|
656
|
+
get_snowflake_facade().grant_privileges_to_role(
|
|
657
|
+
privileges=["usage"],
|
|
658
|
+
object_type=ObjectType.SCHEMA,
|
|
659
|
+
object_identifier=f"{package.name}.{stage_schema}",
|
|
660
|
+
role_to_grant=self.role,
|
|
661
|
+
role_to_use=package.role,
|
|
662
|
+
)
|
|
661
663
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
664
|
+
get_snowflake_facade().grant_privileges_to_role(
|
|
665
|
+
privileges=["read"],
|
|
666
|
+
object_type=ObjectType.STAGE,
|
|
667
|
+
object_identifier=stage_path.stage,
|
|
668
|
+
role_to_grant=self.role,
|
|
669
|
+
role_to_use=package.role,
|
|
670
|
+
)
|
|
669
671
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
672
|
+
return get_snowflake_facade().create_application(
|
|
673
|
+
name=self.name,
|
|
674
|
+
package_name=package.name,
|
|
675
|
+
install_method=install_method,
|
|
676
|
+
path_to_version_directory=stage_path.full_path,
|
|
677
|
+
debug_mode=self.debug,
|
|
678
|
+
should_authorize_event_sharing=event_sharing.should_authorize_event_sharing(),
|
|
679
|
+
role=self.role,
|
|
680
|
+
warehouse=self.warehouse,
|
|
681
|
+
release_channel=release_channel,
|
|
682
|
+
)
|
|
680
683
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
684
|
+
@span("update_app_object")
|
|
685
|
+
def create_or_upgrade_app(
|
|
686
|
+
self,
|
|
687
|
+
package: ApplicationPackageEntity,
|
|
688
|
+
stage_path: DefaultStagePathParts,
|
|
689
|
+
install_method: SameAccountInstallMethod,
|
|
690
|
+
policy: PolicyBase,
|
|
691
|
+
interactive: bool,
|
|
692
|
+
release_channel: Optional[str] = None,
|
|
693
|
+
):
|
|
694
|
+
event_sharing = EventSharingHandler(
|
|
695
|
+
telemetry_definition=self.telemetry,
|
|
696
|
+
deploy_root=package.deploy_root,
|
|
697
|
+
install_method=install_method,
|
|
698
|
+
console=self.console,
|
|
699
|
+
)
|
|
686
700
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
event_sharing.should_authorize_event_sharing_after_upgrade(
|
|
692
|
-
app_properties,
|
|
693
|
-
)
|
|
694
|
-
)
|
|
695
|
-
if new_authorize_event_sharing_value is not None:
|
|
696
|
-
log.info(
|
|
697
|
-
"Setting telemetry sharing authorization to %s",
|
|
698
|
-
new_authorize_event_sharing_value,
|
|
699
|
-
)
|
|
700
|
-
sql_executor.execute_query(
|
|
701
|
-
f"alter application {self.name} set AUTHORIZE_TELEMETRY_EVENT_SHARING = {str(new_authorize_event_sharing_value).upper()}"
|
|
702
|
-
)
|
|
703
|
-
events_to_share = event_sharing.events_to_share(
|
|
704
|
-
events_definitions
|
|
705
|
-
)
|
|
706
|
-
if events_to_share is not None:
|
|
707
|
-
get_snowflake_facade().share_telemetry_events(
|
|
708
|
-
self.name, events_to_share
|
|
709
|
-
)
|
|
710
|
-
|
|
711
|
-
if install_method.is_dev_mode:
|
|
712
|
-
# if debug_mode is present (controlled), ensure it is up-to-date
|
|
713
|
-
if debug_mode is not None:
|
|
714
|
-
sql_executor.execute_query(
|
|
715
|
-
f"alter application {self.name} set debug_mode = {debug_mode}"
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
# hooks always executed after a create or upgrade
|
|
719
|
-
self.execute_post_deploy_hooks()
|
|
720
|
-
return
|
|
721
|
-
|
|
722
|
-
except ProgrammingError as err:
|
|
723
|
-
if err.errno == CANNOT_DISABLE_MANDATORY_TELEMETRY:
|
|
724
|
-
event_sharing.event_sharing_error(
|
|
725
|
-
"Could not disable telemetry event sharing for the application because it contains mandatory events. Please set 'share_mandatory_events' to true in the application telemetry section of the project definition file.",
|
|
726
|
-
err,
|
|
727
|
-
)
|
|
728
|
-
elif err.errno in UPGRADE_RESTRICTION_CODES:
|
|
729
|
-
console.warning(err.msg)
|
|
730
|
-
self.drop_application_before_upgrade(
|
|
731
|
-
policy=policy, interactive=interactive
|
|
732
|
-
)
|
|
733
|
-
else:
|
|
734
|
-
generic_sql_error_handler(err=err)
|
|
735
|
-
|
|
736
|
-
# 4. With no (more) existing application objects, create an application object using the release directives
|
|
737
|
-
console.step(f"Creating new application object {self.name} in account.")
|
|
738
|
-
|
|
739
|
-
if self.role != package.role:
|
|
740
|
-
with sql_executor.use_role(package.role):
|
|
741
|
-
sql_executor.execute_query(
|
|
742
|
-
f"grant install, develop on application package {package.name} to role {self.role}"
|
|
743
|
-
)
|
|
744
|
-
sql_executor.execute_query(
|
|
745
|
-
f"grant usage on schema {package.name}.{stage_schema} to role {self.role}"
|
|
746
|
-
)
|
|
747
|
-
sql_executor.execute_query(
|
|
748
|
-
f"grant read on stage {stage_fqn} to role {self.role}"
|
|
749
|
-
)
|
|
701
|
+
# 1. Check for an existing application by the same name
|
|
702
|
+
show_app_row = get_snowflake_facade().get_existing_app_info(
|
|
703
|
+
self.name, self.role
|
|
704
|
+
)
|
|
750
705
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
706
|
+
# 2. If existing application is found, try to upgrade the application object.
|
|
707
|
+
create_or_upgrade_result = None
|
|
708
|
+
if show_app_row:
|
|
709
|
+
create_or_upgrade_result = self._upgrade_app(
|
|
710
|
+
stage_path=stage_path,
|
|
711
|
+
install_method=install_method,
|
|
712
|
+
event_sharing=event_sharing,
|
|
713
|
+
policy=policy,
|
|
714
|
+
interactive=interactive,
|
|
715
|
+
release_channel=release_channel,
|
|
716
|
+
)
|
|
760
717
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
authorize_telemetry_clause = f" AUTHORIZE_TELEMETRY_EVENT_SHARING = {str(new_authorize_event_sharing_value).upper()}"
|
|
771
|
-
|
|
772
|
-
using_clause = install_method.using_clause(stage_fqn)
|
|
773
|
-
create_cursor = sql_executor.execute_query(
|
|
774
|
-
dedent(
|
|
775
|
-
f"""\
|
|
776
|
-
create application {self.name}
|
|
777
|
-
from application package {package.name} {using_clause} {debug_mode_clause}{authorize_telemetry_clause}
|
|
778
|
-
comment = {SPECIAL_COMMENT}
|
|
779
|
-
"""
|
|
780
|
-
),
|
|
781
|
-
)
|
|
782
|
-
print_messages(console, create_cursor)
|
|
783
|
-
events_definitions = get_snowflake_facade().get_event_definitions(
|
|
784
|
-
self.name, self.role
|
|
785
|
-
)
|
|
718
|
+
# 3. If no existing application found, or we performed a drop before the upgrade, we proceed to create
|
|
719
|
+
if create_or_upgrade_result is None:
|
|
720
|
+
create_or_upgrade_result = self._create_app(
|
|
721
|
+
stage_path=stage_path,
|
|
722
|
+
install_method=install_method,
|
|
723
|
+
event_sharing=event_sharing,
|
|
724
|
+
package=package,
|
|
725
|
+
release_channel=release_channel,
|
|
726
|
+
)
|
|
786
727
|
|
|
787
|
-
|
|
788
|
-
if events_to_share is not None:
|
|
789
|
-
get_snowflake_facade().share_telemetry_events(
|
|
790
|
-
self.name, events_to_share
|
|
791
|
-
)
|
|
728
|
+
print_messages(self.console, create_or_upgrade_result)
|
|
792
729
|
|
|
793
|
-
|
|
794
|
-
|
|
730
|
+
events_definitions = get_snowflake_facade().get_event_definitions(
|
|
731
|
+
self.name, self.role
|
|
732
|
+
)
|
|
795
733
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
734
|
+
events_to_share = event_sharing.events_to_share(events_definitions)
|
|
735
|
+
if events_to_share is not None:
|
|
736
|
+
get_snowflake_facade().share_telemetry_events(
|
|
737
|
+
self.name, events_to_share, self.role
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
# hooks always executed after a create or upgrade
|
|
741
|
+
self.execute_post_deploy_hooks()
|
|
803
742
|
|
|
804
743
|
def execute_post_deploy_hooks(self):
|
|
805
744
|
execute_post_deploy_hooks(
|
|
806
|
-
console=self.
|
|
745
|
+
console=self.console,
|
|
807
746
|
project_root=self.project_root,
|
|
808
747
|
post_deploy_hooks=self.post_deploy_hooks,
|
|
809
748
|
deployed_object_type="application",
|
|
@@ -827,69 +766,59 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
827
766
|
)
|
|
828
767
|
)
|
|
829
768
|
|
|
830
|
-
def get_existing_app_info(self) -> Optional[dict]:
|
|
831
|
-
"""
|
|
832
|
-
Check for an existing application object by the same name as in project definition, in account.
|
|
833
|
-
It executes a 'show applications like' query and returns the result as single row, if one exists.
|
|
834
|
-
"""
|
|
835
|
-
sql_executor = get_sql_executor()
|
|
836
|
-
with sql_executor.use_role(self.role):
|
|
837
|
-
return sql_executor.show_specific_object(
|
|
838
|
-
"applications", self.name, name_col=NAME_COL
|
|
839
|
-
)
|
|
840
|
-
|
|
841
769
|
def drop_application_before_upgrade(
|
|
842
770
|
self,
|
|
843
771
|
policy: PolicyBase,
|
|
844
772
|
interactive: bool,
|
|
845
773
|
cascade: bool = False,
|
|
846
774
|
):
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
775
|
+
sql_executor = get_sql_executor()
|
|
776
|
+
with sql_executor.use_role(self.role):
|
|
777
|
+
if cascade:
|
|
778
|
+
try:
|
|
779
|
+
if application_objects := self.get_objects_owned_by_application():
|
|
780
|
+
application_objects_str = _application_objects_to_str(
|
|
781
|
+
application_objects
|
|
782
|
+
)
|
|
783
|
+
self.console.message(
|
|
784
|
+
f"The following objects are owned by application {self.name} and need to be dropped:\n{application_objects_str}"
|
|
785
|
+
)
|
|
786
|
+
except ProgrammingError as err:
|
|
787
|
+
if err.errno != APPLICATION_NO_LONGER_AVAILABLE:
|
|
788
|
+
generic_sql_error_handler(err)
|
|
789
|
+
self.console.warning(
|
|
790
|
+
"The application owns other objects but they could not be determined."
|
|
854
791
|
)
|
|
855
|
-
|
|
856
|
-
|
|
792
|
+
user_prompt = "Do you want the Snowflake CLI to drop these objects, then drop the existing application object and recreate it?"
|
|
793
|
+
else:
|
|
794
|
+
user_prompt = "Do you want the Snowflake CLI to drop the existing application object and recreate it?"
|
|
795
|
+
|
|
796
|
+
if not policy.should_proceed(user_prompt):
|
|
797
|
+
if interactive:
|
|
798
|
+
self.console.message("Not upgrading the application object.")
|
|
799
|
+
raise typer.Exit(0)
|
|
800
|
+
else:
|
|
801
|
+
self.console.message(
|
|
802
|
+
"Cannot upgrade the application object non-interactively without --force."
|
|
857
803
|
)
|
|
804
|
+
raise typer.Exit(1)
|
|
805
|
+
try:
|
|
806
|
+
cascade_msg = " (cascade)" if cascade else ""
|
|
807
|
+
self.console.step(
|
|
808
|
+
f"Dropping application object {self.name}{cascade_msg}."
|
|
809
|
+
)
|
|
810
|
+
cascade_sql = " cascade" if cascade else ""
|
|
811
|
+
sql_executor.execute_query(f"drop application {self.name}{cascade_sql}")
|
|
858
812
|
except ProgrammingError as err:
|
|
859
|
-
if err.errno
|
|
813
|
+
if err.errno == APPLICATION_OWNS_EXTERNAL_OBJECTS and not cascade:
|
|
814
|
+
# We need to cascade the deletion, let's try again (only if we didn't try with cascade already)
|
|
815
|
+
return self.drop_application_before_upgrade(
|
|
816
|
+
policy=policy,
|
|
817
|
+
interactive=interactive,
|
|
818
|
+
cascade=True,
|
|
819
|
+
)
|
|
820
|
+
else:
|
|
860
821
|
generic_sql_error_handler(err)
|
|
861
|
-
console.warning(
|
|
862
|
-
"The application owns other objects but they could not be determined."
|
|
863
|
-
)
|
|
864
|
-
user_prompt = "Do you want the Snowflake CLI to drop these objects, then drop the existing application object and recreate it?"
|
|
865
|
-
else:
|
|
866
|
-
user_prompt = "Do you want the Snowflake CLI to drop the existing application object and recreate it?"
|
|
867
|
-
|
|
868
|
-
if not policy.should_proceed(user_prompt):
|
|
869
|
-
if interactive:
|
|
870
|
-
console.message("Not upgrading the application object.")
|
|
871
|
-
raise typer.Exit(0)
|
|
872
|
-
else:
|
|
873
|
-
console.message(
|
|
874
|
-
"Cannot upgrade the application object non-interactively without --force."
|
|
875
|
-
)
|
|
876
|
-
raise typer.Exit(1)
|
|
877
|
-
try:
|
|
878
|
-
cascade_msg = " (cascade)" if cascade else ""
|
|
879
|
-
console.step(f"Dropping application object {self.name}{cascade_msg}.")
|
|
880
|
-
cascade_sql = " cascade" if cascade else ""
|
|
881
|
-
sql_executor = get_sql_executor()
|
|
882
|
-
sql_executor.execute_query(f"drop application {self.name}{cascade_sql}")
|
|
883
|
-
except ProgrammingError as err:
|
|
884
|
-
if err.errno == APPLICATION_OWNS_EXTERNAL_OBJECTS and not cascade:
|
|
885
|
-
# We need to cascade the deletion, let's try again (only if we didn't try with cascade already)
|
|
886
|
-
return self.drop_application_before_upgrade(
|
|
887
|
-
policy=policy,
|
|
888
|
-
interactive=interactive,
|
|
889
|
-
cascade=True,
|
|
890
|
-
)
|
|
891
|
-
else:
|
|
892
|
-
generic_sql_error_handler(err)
|
|
893
822
|
|
|
894
823
|
def get_events(
|
|
895
824
|
self,
|
|
@@ -1043,6 +972,7 @@ class ApplicationEntity(EntityBase[ApplicationEntityModel]):
|
|
|
1043
972
|
except KeyboardInterrupt:
|
|
1044
973
|
return
|
|
1045
974
|
|
|
975
|
+
@span("get_snowsight_url_for_app")
|
|
1046
976
|
def get_snowsight_url(self) -> str:
|
|
1047
977
|
"""Returns the URL that can be used to visit this app via Snowsight."""
|
|
1048
978
|
name = identifier_for_url(self.name)
|