pvw-cli 1.0.12__py3-none-any.whl → 1.2.0__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.
Potentially problematic release.
This version of pvw-cli might be problematic. Click here for more details.
- purviewcli/__init__.py +2 -2
- purviewcli/cli/account.py +24 -24
- purviewcli/cli/cli.py +16 -16
- purviewcli/cli/collections.py +24 -24
- purviewcli/cli/domain.py +8 -8
- purviewcli/cli/entity.py +328 -222
- purviewcli/cli/glossary.py +29 -29
- purviewcli/cli/health.py +2 -2
- purviewcli/cli/insight.py +7 -7
- purviewcli/cli/lineage.py +11 -11
- purviewcli/cli/unified_catalog.py +610 -29
- purviewcli/cli/workflow.py +43 -43
- purviewcli/client/_entity.py +35 -0
- purviewcli/client/_unified_catalog.py +7 -0
- {pvw_cli-1.0.12.dist-info → pvw_cli-1.2.0.dist-info}/METADATA +378 -58
- {pvw_cli-1.0.12.dist-info → pvw_cli-1.2.0.dist-info}/RECORD +19 -19
- {pvw_cli-1.0.12.dist-info → pvw_cli-1.2.0.dist-info}/WHEEL +0 -0
- {pvw_cli-1.0.12.dist-info → pvw_cli-1.2.0.dist-info}/entry_points.txt +0 -0
- {pvw_cli-1.0.12.dist-info → pvw_cli-1.2.0.dist-info}/top_level.txt +0 -0
purviewcli/__init__.py
CHANGED
purviewcli/cli/account.py
CHANGED
|
@@ -38,7 +38,7 @@ def get_account(ctx):
|
|
|
38
38
|
try:
|
|
39
39
|
if ctx.obj.get("mock"):
|
|
40
40
|
console.print("[yellow]🎭 Mock: account get-account command[/yellow]")
|
|
41
|
-
console.print("[green]
|
|
41
|
+
console.print("[green][OK] Mock account get-account completed successfully[/green]")
|
|
42
42
|
return
|
|
43
43
|
|
|
44
44
|
args = {}
|
|
@@ -48,13 +48,13 @@ def get_account(ctx):
|
|
|
48
48
|
result = account_client.accountRead(args)
|
|
49
49
|
|
|
50
50
|
if result:
|
|
51
|
-
console.print("[green]
|
|
51
|
+
console.print("[green][OK] Account information retrieved successfully[/green]")
|
|
52
52
|
console.print(json.dumps(result, indent=2))
|
|
53
53
|
else:
|
|
54
|
-
console.print("[yellow]
|
|
54
|
+
console.print("[yellow][!] Account get-account completed with no result[/yellow]")
|
|
55
55
|
|
|
56
56
|
except Exception as e:
|
|
57
|
-
console.print(f"[red]
|
|
57
|
+
console.print(f"[red][X] Error executing account get-account: {str(e)}[/red]")
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
@account.command()
|
|
@@ -64,7 +64,7 @@ def get_access_keys(ctx):
|
|
|
64
64
|
try:
|
|
65
65
|
if ctx.obj.get("mock"):
|
|
66
66
|
console.print("[yellow]🎭 Mock: account get-access-keys command[/yellow]")
|
|
67
|
-
console.print("[green]
|
|
67
|
+
console.print("[green][OK] Mock account get-access-keys completed successfully[/green]")
|
|
68
68
|
return
|
|
69
69
|
|
|
70
70
|
args = {}
|
|
@@ -74,13 +74,13 @@ def get_access_keys(ctx):
|
|
|
74
74
|
result = account_client.accountReadAccessKeys(args)
|
|
75
75
|
|
|
76
76
|
if result:
|
|
77
|
-
console.print("[green]
|
|
77
|
+
console.print("[green][OK] Access keys retrieved successfully[/green]")
|
|
78
78
|
console.print(json.dumps(result, indent=2))
|
|
79
79
|
else:
|
|
80
|
-
console.print("[yellow]
|
|
80
|
+
console.print("[yellow][!] Account get-access-keys completed with no result[/yellow]")
|
|
81
81
|
|
|
82
82
|
except Exception as e:
|
|
83
|
-
console.print(f"[red]
|
|
83
|
+
console.print(f"[red][X] Error executing account get-access-keys: {str(e)}[/red]")
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
@account.command()
|
|
@@ -94,7 +94,7 @@ def regenerate_access_keys(ctx, key_type):
|
|
|
94
94
|
if ctx.obj.get("mock"):
|
|
95
95
|
console.print("[yellow]🎭 Mock: account regenerate-access-keys command[/yellow]")
|
|
96
96
|
console.print(f"[dim]Key Type: {key_type}[/dim]")
|
|
97
|
-
console.print("[green]
|
|
97
|
+
console.print("[green][OK] Mock account regenerate-access-keys completed successfully[/green]")
|
|
98
98
|
return
|
|
99
99
|
|
|
100
100
|
args = {"--keyType": key_type}
|
|
@@ -104,13 +104,13 @@ def regenerate_access_keys(ctx, key_type):
|
|
|
104
104
|
result = account_client.accountRegenerateAccessKey(args)
|
|
105
105
|
|
|
106
106
|
if result:
|
|
107
|
-
console.print("[green]
|
|
107
|
+
console.print("[green][OK] Access keys regenerated successfully[/green]")
|
|
108
108
|
console.print(json.dumps(result, indent=2))
|
|
109
109
|
else:
|
|
110
|
-
console.print("[yellow]
|
|
110
|
+
console.print("[yellow][!] Account regenerate-access-keys completed with no result[/yellow]")
|
|
111
111
|
|
|
112
112
|
except Exception as e:
|
|
113
|
-
console.print(f"[red]
|
|
113
|
+
console.print(f"[red][X] Error executing account regenerate-access-keys: {str(e)}[/red]")
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
@account.command()
|
|
@@ -122,7 +122,7 @@ def update_account(ctx, friendly_name):
|
|
|
122
122
|
if ctx.obj.get("mock"):
|
|
123
123
|
console.print("[yellow]🎭 Mock: account update-account command[/yellow]")
|
|
124
124
|
console.print(f"[dim]Friendly Name: {friendly_name}[/dim]")
|
|
125
|
-
console.print("[green]
|
|
125
|
+
console.print("[green][OK] Mock account update-account completed successfully[/green]")
|
|
126
126
|
return
|
|
127
127
|
|
|
128
128
|
args = {"--friendlyName": friendly_name}
|
|
@@ -132,13 +132,13 @@ def update_account(ctx, friendly_name):
|
|
|
132
132
|
result = account_client.accountUpdate(args)
|
|
133
133
|
|
|
134
134
|
if result:
|
|
135
|
-
console.print("[green]
|
|
135
|
+
console.print("[green][OK] Account updated successfully[/green]")
|
|
136
136
|
console.print(json.dumps(result, indent=2))
|
|
137
137
|
else:
|
|
138
|
-
console.print("[yellow]
|
|
138
|
+
console.print("[yellow][!] Account update-account completed with no result[/yellow]")
|
|
139
139
|
|
|
140
140
|
except Exception as e:
|
|
141
|
-
console.print(f"[red]
|
|
141
|
+
console.print(f"[red][X] Error executing account update-account: {str(e)}[/red]")
|
|
142
142
|
|
|
143
143
|
|
|
144
144
|
@account.command()
|
|
@@ -148,7 +148,7 @@ def get_collections(ctx):
|
|
|
148
148
|
try:
|
|
149
149
|
if ctx.obj.get("mock"):
|
|
150
150
|
console.print("[yellow]🎭 Mock: account get-collections command[/yellow]")
|
|
151
|
-
console.print("[green]
|
|
151
|
+
console.print("[green][OK] Mock account get-collections completed successfully[/green]")
|
|
152
152
|
return
|
|
153
153
|
|
|
154
154
|
args = {}
|
|
@@ -158,13 +158,13 @@ def get_collections(ctx):
|
|
|
158
158
|
result = account_client.collectionsRead(args)
|
|
159
159
|
|
|
160
160
|
if result:
|
|
161
|
-
console.print("[green]
|
|
161
|
+
console.print("[green][OK] Collections retrieved successfully[/green]")
|
|
162
162
|
console.print(json.dumps(result, indent=2))
|
|
163
163
|
else:
|
|
164
|
-
console.print("[yellow]
|
|
164
|
+
console.print("[yellow][!] Account get-collections completed with no result[/yellow]")
|
|
165
165
|
|
|
166
166
|
except Exception as e:
|
|
167
|
-
console.print(f"[red]
|
|
167
|
+
console.print(f"[red][X] Error executing account get-collections: {str(e)}[/red]")
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
@account.command()
|
|
@@ -176,7 +176,7 @@ def get_collection(ctx, collection_name):
|
|
|
176
176
|
if ctx.obj.get("mock"):
|
|
177
177
|
console.print("[yellow]🎭 Mock: account get-collection command[/yellow]")
|
|
178
178
|
console.print(f"[dim]Collection Name: {collection_name}[/dim]")
|
|
179
|
-
console.print("[green]
|
|
179
|
+
console.print("[green][OK] Mock account get-collection completed successfully[/green]")
|
|
180
180
|
return
|
|
181
181
|
|
|
182
182
|
args = {"--collectionName": collection_name}
|
|
@@ -186,13 +186,13 @@ def get_collection(ctx, collection_name):
|
|
|
186
186
|
result = account_client.collectionsRead(args)
|
|
187
187
|
|
|
188
188
|
if result:
|
|
189
|
-
console.print("[green]
|
|
189
|
+
console.print("[green][OK] Collection information retrieved successfully[/green]")
|
|
190
190
|
console.print(json.dumps(result, indent=2))
|
|
191
191
|
else:
|
|
192
|
-
console.print("[yellow]
|
|
192
|
+
console.print("[yellow][!] Account get-collection completed with no result[/yellow]")
|
|
193
193
|
|
|
194
194
|
except Exception as e:
|
|
195
|
-
console.print(f"[red]
|
|
195
|
+
console.print(f"[red][X] Error executing account get-collection: {str(e)}[/red]")
|
|
196
196
|
|
|
197
197
|
|
|
198
198
|
# Make the account group available for import
|
purviewcli/cli/cli.py
CHANGED
|
@@ -38,97 +38,97 @@ def register_individual_cli_modules(main_group):
|
|
|
38
38
|
|
|
39
39
|
main_group.add_command(lineage)
|
|
40
40
|
except ImportError as e:
|
|
41
|
-
console.print(f"[yellow]
|
|
41
|
+
console.print(f"[yellow][!] Could not import lineage CLI module: {e}[/yellow]")
|
|
42
42
|
try:
|
|
43
43
|
from .account import account
|
|
44
44
|
|
|
45
45
|
main_group.add_command(account)
|
|
46
46
|
except ImportError as e:
|
|
47
|
-
console.print(f"[yellow]
|
|
47
|
+
console.print(f"[yellow][!] Could not import account CLI module: {e}[/yellow]")
|
|
48
48
|
try:
|
|
49
49
|
from .entity import entity
|
|
50
50
|
|
|
51
51
|
main_group.add_command(entity)
|
|
52
52
|
except ImportError as e:
|
|
53
|
-
console.print(f"[yellow]
|
|
53
|
+
console.print(f"[yellow][!] Could not import entity CLI module: {e}[/yellow]")
|
|
54
54
|
try:
|
|
55
55
|
from .insight import insight
|
|
56
56
|
|
|
57
57
|
main_group.add_command(insight)
|
|
58
58
|
except ImportError as e:
|
|
59
|
-
console.print(f"[yellow]
|
|
59
|
+
console.print(f"[yellow][!] Could not import insight CLI module: {e}[/yellow]")
|
|
60
60
|
try:
|
|
61
61
|
from .glossary import glossary
|
|
62
62
|
|
|
63
63
|
main_group.add_command(glossary)
|
|
64
64
|
except ImportError as e:
|
|
65
|
-
console.print(f"[yellow]
|
|
65
|
+
console.print(f"[yellow][!] Could not import glossary CLI module: {e}[/yellow]")
|
|
66
66
|
try:
|
|
67
67
|
from .management import management
|
|
68
68
|
|
|
69
69
|
main_group.add_command(management)
|
|
70
70
|
except ImportError as e:
|
|
71
|
-
console.print(f"[yellow]
|
|
71
|
+
console.print(f"[yellow][!] Could not import management CLI module: {e}[/yellow]")
|
|
72
72
|
try:
|
|
73
73
|
from .policystore import policystore
|
|
74
74
|
|
|
75
75
|
main_group.add_command(policystore)
|
|
76
76
|
except ImportError as e:
|
|
77
|
-
console.print(f"[yellow]
|
|
77
|
+
console.print(f"[yellow][!] Could not import policystore CLI module: {e}[/yellow]")
|
|
78
78
|
try:
|
|
79
79
|
from .relationship import relationship
|
|
80
80
|
|
|
81
81
|
main_group.add_command(relationship)
|
|
82
82
|
except ImportError as e:
|
|
83
|
-
console.print(f"[yellow]
|
|
83
|
+
console.print(f"[yellow][!] Could not import relationship CLI module: {e}[/yellow]")
|
|
84
84
|
try:
|
|
85
85
|
from .scan import scan
|
|
86
86
|
|
|
87
87
|
main_group.add_command(scan)
|
|
88
88
|
|
|
89
89
|
except ImportError as e:
|
|
90
|
-
console.print(f"[yellow]
|
|
90
|
+
console.print(f"[yellow][!] Could not import scan CLI module: {e}[/yellow]")
|
|
91
91
|
try:
|
|
92
92
|
from .search import search
|
|
93
93
|
|
|
94
94
|
main_group.add_command(search)
|
|
95
95
|
except ImportError as e:
|
|
96
|
-
console.print(f"[yellow]
|
|
96
|
+
console.print(f"[yellow][!] Could not import search CLI module: {e}[/yellow]")
|
|
97
97
|
try:
|
|
98
98
|
from .share import share
|
|
99
99
|
|
|
100
100
|
main_group.add_command(share)
|
|
101
101
|
except ImportError as e:
|
|
102
|
-
console.print(f"[yellow]
|
|
102
|
+
console.print(f"[yellow][!] Could not import share CLI module: {e}[/yellow]")
|
|
103
103
|
try:
|
|
104
104
|
from .types import types
|
|
105
105
|
main_group.add_command(types)
|
|
106
106
|
except ImportError as e:
|
|
107
|
-
console.print(f"[yellow]
|
|
107
|
+
console.print(f"[yellow][!] Could not import types CLI module: {e}[/yellow]")
|
|
108
108
|
try:
|
|
109
109
|
from .collections import collections
|
|
110
110
|
main_group.add_command(collections, name="collections")
|
|
111
111
|
# Removed domain alias to avoid conflicts with dedicated domain module
|
|
112
112
|
except ImportError as e:
|
|
113
|
-
console.print(f"[yellow]
|
|
113
|
+
console.print(f"[yellow][!] Could not import collections CLI module: {e}[/yellow]")
|
|
114
114
|
try:
|
|
115
115
|
from .unified_catalog import uc
|
|
116
116
|
|
|
117
117
|
main_group.add_command(uc) # Main Unified Catalog command
|
|
118
118
|
except ImportError as e:
|
|
119
|
-
console.print(f"[yellow]
|
|
119
|
+
console.print(f"[yellow][!] Could not import unified catalog (uc) CLI module: {e}[/yellow]")
|
|
120
120
|
try:
|
|
121
121
|
from .domain import domain
|
|
122
122
|
|
|
123
123
|
main_group.add_command(domain)
|
|
124
124
|
except ImportError as e:
|
|
125
|
-
console.print(f"[yellow]
|
|
125
|
+
console.print(f"[yellow][!] Could not import domain CLI module: {e}[/yellow]")
|
|
126
126
|
try:
|
|
127
127
|
from .workflow import workflow
|
|
128
128
|
|
|
129
129
|
main_group.add_command(workflow)
|
|
130
130
|
except ImportError as e:
|
|
131
|
-
console.print(f"[yellow]
|
|
131
|
+
console.print(f"[yellow][!] Could not import workflow CLI module: {e}[/yellow]")
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
@click.group()
|
purviewcli/cli/collections.py
CHANGED
|
@@ -169,7 +169,7 @@ def list_detailed(ctx, output_format, include_assets, include_scans, max_depth):
|
|
|
169
169
|
collections_result = collections_client.collectionsRead({})
|
|
170
170
|
|
|
171
171
|
if not collections_result or "value" not in collections_result:
|
|
172
|
-
console.print("[yellow]
|
|
172
|
+
console.print("[yellow][!] No collections found[/yellow]")
|
|
173
173
|
return
|
|
174
174
|
|
|
175
175
|
collections_data = collections_result["value"]
|
|
@@ -183,7 +183,7 @@ def list_detailed(ctx, output_format, include_assets, include_scans, max_depth):
|
|
|
183
183
|
_display_collections_table(collections_data, include_assets, include_scans)
|
|
184
184
|
|
|
185
185
|
except Exception as e:
|
|
186
|
-
console.print(f"[red]
|
|
186
|
+
console.print(f"[red][X] Error in collections list-detailed: {str(e)}[/red]")
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
@collections.command("get-details")
|
|
@@ -222,7 +222,7 @@ def get_details(ctx, collection_name, include_assets, include_data_sources, incl
|
|
|
222
222
|
|
|
223
223
|
collection_info = collections_client.collectionsRead({"--name": collection_name})
|
|
224
224
|
if not collection_info:
|
|
225
|
-
console.print(f"[red]
|
|
225
|
+
console.print(f"[red][X] Collection '{collection_name}' not found[/red]")
|
|
226
226
|
return
|
|
227
227
|
|
|
228
228
|
# Display basic collection info
|
|
@@ -230,22 +230,22 @@ def get_details(ctx, collection_name, include_assets, include_data_sources, incl
|
|
|
230
230
|
|
|
231
231
|
# Get assets if requested
|
|
232
232
|
if include_assets:
|
|
233
|
-
console.print(f"[blue]
|
|
233
|
+
console.print(f"[blue][*] Retrieving assets (limit: {asset_limit})...[/blue]")
|
|
234
234
|
assets = _get_collection_assets(search_client, collection_name, asset_limit)
|
|
235
235
|
_display_asset_summary(assets)
|
|
236
236
|
|
|
237
237
|
# Get data sources if requested
|
|
238
238
|
if include_data_sources:
|
|
239
239
|
console.print("[blue]🔌 Retrieving data sources...[/blue]")
|
|
240
|
-
console.print("[yellow]
|
|
240
|
+
console.print("[yellow][!] Data source information feature coming soon[/yellow]")
|
|
241
241
|
|
|
242
242
|
# Get scan information if requested
|
|
243
243
|
if include_scans:
|
|
244
|
-
console.print("[blue]
|
|
245
|
-
console.print("[yellow]
|
|
244
|
+
console.print("[blue][*] Retrieving scan information...[/blue]")
|
|
245
|
+
console.print("[yellow][!] Scan information feature coming soon[/yellow]")
|
|
246
246
|
|
|
247
247
|
except Exception as e:
|
|
248
|
-
console.print(f"[red]
|
|
248
|
+
console.print(f"[red][X] Error in collections get-details: {str(e)}[/red]")
|
|
249
249
|
|
|
250
250
|
|
|
251
251
|
@collections.command("force-delete")
|
|
@@ -287,13 +287,13 @@ def force_delete(ctx, collection_name, delete_assets, delete_data_sources,
|
|
|
287
287
|
console = Console()
|
|
288
288
|
|
|
289
289
|
if dry_run:
|
|
290
|
-
console.print(f"[yellow]
|
|
290
|
+
console.print(f"[yellow][*] DRY RUN: Analyzing collection '{collection_name}' for deletion[/yellow]")
|
|
291
291
|
|
|
292
292
|
# Mathematical optimization validation (from PowerShell scripts)
|
|
293
293
|
if delete_assets and batch_size > 0:
|
|
294
294
|
assets_per_job = 1000 // max_parallel # Default total per batch cycle
|
|
295
295
|
api_calls_per_job = assets_per_job // batch_size
|
|
296
|
-
console.print(f"[blue]
|
|
296
|
+
console.print(f"[blue][*] Optimization: {max_parallel} parallel jobs, {assets_per_job} assets/job, {api_calls_per_job} API calls/job[/blue]")
|
|
297
297
|
|
|
298
298
|
collections_client = Collections()
|
|
299
299
|
entity_client = Entity()
|
|
@@ -302,36 +302,36 @@ def force_delete(ctx, collection_name, delete_assets, delete_data_sources,
|
|
|
302
302
|
# Step 1: Verify collection exists
|
|
303
303
|
collection_info = collections_client.collectionsRead({"--collectionName": collection_name})
|
|
304
304
|
if not collection_info:
|
|
305
|
-
console.print(f"[red]
|
|
305
|
+
console.print(f"[red][X] Collection '{collection_name}' not found[/red]")
|
|
306
306
|
return
|
|
307
307
|
|
|
308
308
|
# Step 2: Delete assets if requested
|
|
309
309
|
if delete_assets:
|
|
310
|
-
console.print(f"[blue]
|
|
310
|
+
console.print(f"[blue][DEL] {'[DRY RUN] ' if dry_run else ''}Deleting assets in collection...[/blue]")
|
|
311
311
|
deleted_count = _bulk_delete_collection_assets(
|
|
312
312
|
search_client, entity_client, collection_name,
|
|
313
313
|
batch_size, max_parallel, dry_run
|
|
314
314
|
)
|
|
315
|
-
console.print(f"[green]
|
|
315
|
+
console.print(f"[green][OK] {'Would delete' if dry_run else 'Deleted'} {deleted_count} assets[/green]")
|
|
316
316
|
|
|
317
317
|
# Step 3: Delete data sources if requested
|
|
318
318
|
if delete_data_sources:
|
|
319
319
|
console.print(f"[blue]🔌 {'[DRY RUN] ' if dry_run else ''}Deleting data sources...[/blue]")
|
|
320
|
-
console.print("[yellow]
|
|
320
|
+
console.print("[yellow][!] Data source deletion feature coming soon[/yellow]")
|
|
321
321
|
|
|
322
322
|
# Step 4: Delete the collection itself
|
|
323
323
|
if not dry_run:
|
|
324
|
-
console.print(f"[blue]
|
|
324
|
+
console.print(f"[blue][DEL] Deleting collection '{collection_name}'...[/blue]")
|
|
325
325
|
result = collections_client.collectionsDelete({"--collectionName": collection_name})
|
|
326
326
|
if result:
|
|
327
|
-
console.print(f"[green]
|
|
327
|
+
console.print(f"[green][OK] Collection '{collection_name}' deleted successfully[/green]")
|
|
328
328
|
else:
|
|
329
|
-
console.print(f"[yellow]
|
|
329
|
+
console.print(f"[yellow][!] Collection deletion completed with no result[/yellow]")
|
|
330
330
|
else:
|
|
331
|
-
console.print(f"[yellow]
|
|
331
|
+
console.print(f"[yellow][*] DRY RUN: Would delete collection '{collection_name}'[/yellow]")
|
|
332
332
|
|
|
333
333
|
except Exception as e:
|
|
334
|
-
console.print(f"[red]
|
|
334
|
+
console.print(f"[red][X] Error in collections force-delete: {str(e)}[/red]")
|
|
335
335
|
|
|
336
336
|
|
|
337
337
|
# === HELPER FUNCTIONS ===
|
|
@@ -441,10 +441,10 @@ def _display_asset_summary(assets):
|
|
|
441
441
|
|
|
442
442
|
console = Console()
|
|
443
443
|
if not assets:
|
|
444
|
-
console.print("[yellow]
|
|
444
|
+
console.print("[yellow][!] No assets found in collection[/yellow]")
|
|
445
445
|
return
|
|
446
446
|
|
|
447
|
-
console.print(f"[green]
|
|
447
|
+
console.print(f"[green][OK] Found {len(assets)} assets[/green]")
|
|
448
448
|
# Would display asset type breakdown, etc.
|
|
449
449
|
|
|
450
450
|
|
|
@@ -462,7 +462,7 @@ def _bulk_delete_collection_assets(search_client, entity_client, collection_name
|
|
|
462
462
|
console = Console()
|
|
463
463
|
|
|
464
464
|
# Step 1: Get all asset GUIDs in the collection
|
|
465
|
-
console.print("[blue]
|
|
465
|
+
console.print("[blue][*] Finding all assets in collection...[/blue]")
|
|
466
466
|
|
|
467
467
|
# This would use search API to get all assets
|
|
468
468
|
# For now, return mock count
|
|
@@ -471,7 +471,7 @@ def _bulk_delete_collection_assets(search_client, entity_client, collection_name
|
|
|
471
471
|
if total_assets == 0:
|
|
472
472
|
return 0
|
|
473
473
|
|
|
474
|
-
console.print(f"[blue]
|
|
474
|
+
console.print(f"[blue][INFO] Found {total_assets} assets to delete[/blue]")
|
|
475
475
|
|
|
476
476
|
if dry_run:
|
|
477
477
|
return total_assets
|
|
@@ -480,7 +480,7 @@ def _bulk_delete_collection_assets(search_client, entity_client, collection_name
|
|
|
480
480
|
assets_per_job = math.ceil(total_assets / max_parallel)
|
|
481
481
|
api_calls_per_job = math.ceil(assets_per_job / batch_size)
|
|
482
482
|
|
|
483
|
-
console.print(f"[blue]
|
|
483
|
+
console.print(f"[blue][*] Parallel execution: {max_parallel} jobs, {assets_per_job} assets/job, {api_calls_per_job} API calls/job[/blue]")
|
|
484
484
|
|
|
485
485
|
# Step 3: Execute parallel bulk deletions
|
|
486
486
|
deleted_count = 0
|
purviewcli/cli/domain.py
CHANGED
|
@@ -253,12 +253,12 @@ def create_using_collections(domain_name, show_examples):
|
|
|
253
253
|
console.print("\n[bold blue]📋 Creating Domain-like Structures with Microsoft Purview Collections[/bold blue]")
|
|
254
254
|
console.print("\n[yellow]OVERVIEW:[/yellow] Since governance domains are not available in the public API, you can use collections to create hierarchical, domain-like organizational structures.")
|
|
255
255
|
|
|
256
|
-
console.print("\n[cyan]
|
|
257
|
-
console.print("
|
|
258
|
-
console.print("
|
|
259
|
-
console.print("
|
|
260
|
-
console.print("
|
|
261
|
-
console.print("
|
|
256
|
+
console.print("\n[cyan][*] COLLECTIONS AS DOMAINS - KEY CAPABILITIES:[/cyan]")
|
|
257
|
+
console.print("[OK] [green]Hierarchical Organization:[/green] Create nested collections up to 8 levels deep")
|
|
258
|
+
console.print("[OK] [green]Custom Naming:[/green] Use friendly names (up to 100 chars) and descriptions")
|
|
259
|
+
console.print("[OK] [green]Security Boundaries:[/green] Role-based access control per collection")
|
|
260
|
+
console.print("[OK] [green]Asset Organization:[/green] Group data sources, scans, and assets by business unit")
|
|
261
|
+
console.print("[OK] [green]Metadata Management:[/green] Organize metadata within business contexts")
|
|
262
262
|
|
|
263
263
|
if domain_name:
|
|
264
264
|
console.print(f"\n[cyan]🚀 CREATING DOMAIN-LIKE COLLECTION: '{domain_name}'[/cyan]")
|
|
@@ -339,7 +339,7 @@ def create_using_collections(domain_name, show_examples):
|
|
|
339
339
|
console.print("• Set Data Curator role for metadata management")
|
|
340
340
|
console.print("• Implement least-privilege access model")
|
|
341
341
|
|
|
342
|
-
console.print("\n[cyan]
|
|
342
|
+
console.print("\n[cyan][*] ADDITIONAL ORGANIZATION METHODS:[/cyan]")
|
|
343
343
|
console.print("• [bold]Custom Attributes:[/bold] Tag assets with domain information")
|
|
344
344
|
console.print("• [bold]Glossary Terms:[/bold] Create domain-specific business vocabularies")
|
|
345
345
|
console.print("• [bold]Classifications:[/bold] Apply domain-based data classifications")
|
|
@@ -350,7 +350,7 @@ def create_using_collections(domain_name, show_examples):
|
|
|
350
350
|
console.print("• Search domain assets: [bold]pvw domain search-assets --domain <domain-name>[/bold]")
|
|
351
351
|
console.print("• Check organization options: [bold]pvw domain check-attributes[/bold]")
|
|
352
352
|
|
|
353
|
-
console.print("\n[green]
|
|
353
|
+
console.print("\n[green][OK] NEXT STEPS:[/green]")
|
|
354
354
|
console.print("1. Plan your domain hierarchy based on your organization structure")
|
|
355
355
|
console.print("2. Create your root domain collection")
|
|
356
356
|
console.print("3. Add department and team sub-collections")
|