Skip to content

Commit 8fff3e2

Browse files
pjohari-msyayi0512
andauthored
[Microsoft.DocumentDB] CosmosDB API Version 2025-05-01-preview Release (#8693)
* Generated SDK from azure-rest-api-specs PR * first push of rbac for gremlin cassandra and mongo * added test cases * add resources for cassandra and mongo mi and uploaded tests results for cassandra and gremlin * change from mongoMI to mongo_mi * fixed mongo test failure and add generated yaml files * fixed the style * Tests recording. 5 tests remaining * Existing linter errors. Fixed * Missing recordings * Added throughput bucketing recording * All recordings * Nit * Nit - help * Flake8 changes * Reverting the resource group change --------- Co-authored-by: Yi Yang (from Dev Box) <yayi@microsoft.com>
1 parent 97d9662 commit 8fff3e2

190 files changed

Lines changed: 164796 additions & 139297 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/cosmosdb-preview/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
.. :changelog:
22
Release History
33
===============
4+
1.5.0
5+
* Add support for Gremlin/Cassandra/Mongo RBAC role definition and assignment CRUD actions.
6+
7+
+++++++
48
1.4.0
59
* Add support for private endpoint in VPN based datacenter deployments in managed cassandra.
610

src/cosmosdb-preview/azext_cosmosdb_preview/_client_factory.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ def cf_gremlin_resources(cli_ctx, _):
4040
return cf_cosmosdb_preview(cli_ctx).gremlin_resources
4141

4242

43+
def cf_cassandra_resources(cli_ctx, _):
44+
return cf_cosmosdb_preview(cli_ctx).cassandra_resources
45+
46+
47+
def cf_mongo_mi_resources(cli_ctx, _):
48+
return cf_cosmosdb_preview(cli_ctx).mongo_mi_resources
49+
50+
4351
def cf_table_resources(cli_ctx, _):
4452
return cf_cosmosdb_preview(cli_ctx).table_resources
4553

src/cosmosdb-preview/azext_cosmosdb_preview/_help.py

Lines changed: 463 additions & 1 deletion
Large diffs are not rendered by default.

src/cosmosdb-preview/azext_cosmosdb_preview/_params.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@
2020
validate_mongo_user_definition_id,
2121
validate_table_role_definition_body,
2222
validate_table_role_definition_id,
23-
validate_table_role_assignment_id)
23+
validate_table_role_assignment_id,
24+
validate_gremlin_role_definition_body,
25+
validate_gremlin_role_definition_id,
26+
validate_gremlin_role_assignment_id,
27+
validate_cassandra_role_definition_body,
28+
validate_cassandra_role_definition_id,
29+
validate_cassandra_role_assignment_id,
30+
validate_mongoMI_role_definition_body,
31+
validate_mongoMI_role_definition_id,
32+
validate_mongoMI_role_assignment_id)
2433

2534
from azext_cosmosdb_preview.actions import (
2635
CreateGremlinDatabaseRestoreResource,
@@ -76,6 +85,60 @@
7685
}"
7786
"""
7887

88+
GREMLIN_ROLE_DEFINITION_EXAMPLE = """--body "{
89+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
90+
\\"RoleName\\": \\"MyTestRole\\",
91+
\\"type\\": \\"CustomRole\\",
92+
\\"description\\": \\"Custom role to read Cosmos DB metadata\\",
93+
\\"AssignableScopes\\":[\\"/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\"],
94+
\\"Permissions\\": [{\\"dataActions\\": [\\"Microsoft.DocumentDB/databaseAccounts/readMetadata\\"]}]
95+
}"
96+
"""
97+
98+
GREMLIN_ROLE_ASSIGNMENT_EXAMPLE = """--body "{
99+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
100+
\\"RoleDefinitionId\\": \\"MyTestRoleAssignment\\",
101+
\\"PrincipalId\\": \\"efc9875a-2cc4-40d5-8958-566017875b39\\",
102+
\\"Scope\\":\\"/subscriptions/cfe9875a-2cc4-40d5-8958-566017875b39/resourceGroups/MyResourceGroup/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\",
103+
}"
104+
"""
105+
106+
CASSANDRA_ROLE_DEFINITION_EXAMPLE = """--body "{
107+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
108+
\\"RoleName\\": \\"MyTestRole\\",
109+
\\"type\\": \\"CustomRole\\",
110+
\\"description\\": \\"Custom role to read Cosmos DB metadata\\",
111+
\\"AssignableScopes\\":[\\"/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\"],
112+
\\"Permissions\\": [{\\"dataActions\\": [\\"Microsoft.DocumentDB/databaseAccounts/readMetadata\\"]}]
113+
}"
114+
"""
115+
116+
CASSANDRA_ROLE_ASSIGNMENT_EXAMPLE = """--body "{
117+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
118+
\\"RoleDefinitionId\\": \\"MyTestRoleAssignment\\",
119+
\\"PrincipalId\\": \\"efc9875a-2cc4-40d5-8958-566017875b39\\",
120+
\\"Scope\\":\\"/subscriptions/cfe9875a-2cc4-40d5-8958-566017875b39/resourceGroups/MyResourceGroup/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\",
121+
}"
122+
"""
123+
124+
MONGOMI_ROLE_DEFINITION_EXAMPLE = """--body "{
125+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
126+
\\"RoleName\\": \\"MyTestRole\\",
127+
\\"type\\": \\"CustomRole\\",
128+
\\"description\\": \\"Custom role to read Cosmos DB metadata\\",
129+
\\"AssignableScopes\\":[\\"/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\"],
130+
\\"Permissions\\": [{\\"dataActions\\": [\\"Microsoft.DocumentDB/databaseAccounts/readMetadata\\"]}]
131+
}"
132+
"""
133+
134+
MONGOMI_ROLE_ASSIGNMENT_EXAMPLE = """--body "{
135+
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
136+
\\"RoleDefinitionId\\": \\"MyTestRoleAssignment\\",
137+
\\"PrincipalId\\": \\"efc9875a-2cc4-40d5-8958-566017875b39\\",
138+
\\"Scope\\":\\"/subscriptions/cfe9875a-2cc4-40d5-8958-566017875b39/resourceGroups/MyResourceGroup/providers/Microsoft.DocumentDB/databaseAccounts/MyDBAccountName\\",
139+
}"
140+
"""
141+
79142
MONGO_ROLE_DEFINITION_EXAMPLE = """--body "{
80143
\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",
81144
\\"RoleName\\": \\"MyRWRole\\",
@@ -689,3 +752,45 @@ def load_arguments(self, _):
689752
c.argument('role_definition_name', options_list=['--role-definition-name', '-n'], help="Unique Name of the Role Definition that this Role Assignment refers to. Eg. 'Contoso Reader Role'.")
690753
c.argument('scope', options_list=['--scope', '-s'], help="Data plane resource path at which this Role Assignment is being granted.")
691754
c.argument('principal_id', options_list=['--principal-id', '-p'], help="AAD Object ID of the principal to which this Role Assignment is being granted.")
755+
756+
# gremlin role definition
757+
with self.argument_context('cosmosdb gremlin role definition') as c:
758+
c.argument('account_name', account_name_type, id_part=None)
759+
c.argument('role_definition_id', options_list=['--role-definition-id', '-i'], validator=validate_gremlin_role_definition_id, help="Unique ID for the Gremlin Role Definition.")
760+
c.argument('gremlin_role_definition_body', options_list=['--body', '-b'], validator=validate_gremlin_role_definition_body, completer=FilesCompleter(), help="Role Definition body with Id (Optional for create), Type (Default is CustomRole), RoleName, Description, AssignableScopes, Permissions. You can enter it as a string or as a file, e.g., --body @gremlin-role_definition-body-file.json or " + GREMLIN_ROLE_DEFINITION_EXAMPLE)
761+
762+
with self.argument_context('cosmosdb gremlin role assignment') as c:
763+
c.argument('account_name', account_name_type, id_part=None)
764+
c.argument('role_assignment_id', options_list=['--role-assignment-id', '-i'], validator=validate_gremlin_role_assignment_id, help="Optional for Create. Unique ID for the Role Assignment. If not provided, a new GUID will be used.")
765+
c.argument('role_definition_id', options_list=['--role-definition-id', '-d'], help="Unique ID of the Role Definition that this Role Assignment refers to.")
766+
c.argument('role_definition_name', options_list=['--role-definition-name', '-n'], help="Unique Name of the Role Definition that this Role Assignment refers to. Eg. 'Contoso Reader Role'.")
767+
c.argument('scope', options_list=['--scope', '-s'], help="Data plane resource path at which this Role Assignment is being granted.")
768+
c.argument('principal_id', options_list=['--principal-id', '-p'], help="AAD Object ID of the principal to which this Role Assignment is being granted.")
769+
770+
# cassandra role definition
771+
with self.argument_context('cosmosdb cassandra role definition') as c:
772+
c.argument('account_name', account_name_type, id_part=None)
773+
c.argument('role_definition_id', options_list=['--role-definition-id', '-i'], validator=validate_cassandra_role_definition_id, help="Unique ID for the Cassandra Role Definition.")
774+
c.argument('cassandra_role_definition_body', options_list=['--body', '-b'], validator=validate_cassandra_role_definition_body, completer=FilesCompleter(), help="Role Definition body with Id (Optional for create), Type (Default is CustomRole), RoleName, Description, AssignableScopes, Permissions. You can enter it as a string or as a file, e.g., --body @cassandra-role_definition-body-file.json or " + GREMLIN_ROLE_DEFINITION_EXAMPLE)
775+
776+
with self.argument_context('cosmosdb cassandra role assignment') as c:
777+
c.argument('account_name', account_name_type, id_part=None)
778+
c.argument('role_assignment_id', options_list=['--role-assignment-id', '-i'], validator=validate_cassandra_role_assignment_id, help="Optional for Create. Unique ID for the Role Assignment. If not provided, a new GUID will be used.")
779+
c.argument('role_definition_id', options_list=['--role-definition-id', '-d'], help="Unique ID of the Role Definition that this Role Assignment refers to.")
780+
c.argument('role_definition_name', options_list=['--role-definition-name', '-n'], help="Unique Name of the Role Definition that this Role Assignment refers to. Eg. 'Contoso Reader Role'.")
781+
c.argument('scope', options_list=['--scope', '-s'], help="Data plane resource path at which this Role Assignment is being granted.")
782+
c.argument('principal_id', options_list=['--principal-id', '-p'], help="AAD Object ID of the principal to which this Role Assignment is being granted.")
783+
784+
# mongoMI role definition
785+
with self.argument_context('cosmosdb mongomi role definition') as c:
786+
c.argument('account_name', account_name_type, id_part=None)
787+
c.argument('role_definition_id', options_list=['--role-definition-id', '-i'], validator=validate_mongoMI_role_definition_id, help="Unique ID for the MongoMI Role Definition.")
788+
c.argument('mongoMI_role_definition_body', options_list=['--body', '-b'], validator=validate_mongoMI_role_definition_body, completer=FilesCompleter(), help="Role Definition body with Id (Optional for create), Type (Default is CustomRole), RoleName, Description, AssignableScopes, Permissions. You can enter it as a string or as a file, e.g., --body @mongoMI-role_definition-body-file.json or " + GREMLIN_ROLE_DEFINITION_EXAMPLE)
789+
790+
with self.argument_context('cosmosdb mongomi role assignment') as c:
791+
c.argument('account_name', account_name_type, id_part=None)
792+
c.argument('role_assignment_id', options_list=['--role-assignment-id', '-i'], validator=validate_mongoMI_role_assignment_id, help="Optional for Create. Unique ID for the Role Assignment. If not provided, a new GUID will be used.")
793+
c.argument('role_definition_id', options_list=['--role-definition-id', '-d'], help="Unique ID of the Role Definition that this Role Assignment refers to.")
794+
c.argument('role_definition_name', options_list=['--role-definition-name', '-n'], help="Unique Name of the Role Definition that this Role Assignment refers to. Eg. 'Contoso Reader Role'.")
795+
c.argument('scope', options_list=['--scope', '-s'], help="Data plane resource path at which this Role Assignment is being granted.")
796+
c.argument('principal_id', options_list=['--principal-id', '-p'], help="AAD Object ID of the principal to which this Role Assignment is being granted.")

src/cosmosdb-preview/azext_cosmosdb_preview/_validators.py

Lines changed: 145 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,11 +266,11 @@ def validate_table_role_definition_body(cmd, ns):
266266
if 'RoleName' not in table_role_definition or not isinstance(table_role_definition['RoleName'], str) or len(table_role_definition['RoleName']) == 0:
267267
raise InvalidArgumentValueError(
268268
'Role creation failed. Invalid table role name. A valid string role name is expected.')
269-
269+
270270
if 'AssignableScopes' not in table_role_definition or not isinstance(table_role_definition['AssignableScopes'], list) or len(table_role_definition['AssignableScopes']) == 0:
271271
raise InvalidArgumentValueError(
272-
'Role creation failed. Invalid Table role definition for AssignableScopes. A valid list of strings is expected.')
273-
272+
'Role creation failed. Invalid Table role definition for AssignableScopes. A valid list of strings is expected.')
273+
274274
if 'Permissions' not in table_role_definition or not isinstance(table_role_definition['Permissions'], list) or len(table_role_definition['Permissions']) == 0:
275275
raise InvalidArgumentValueError(
276276
'Role creation failed. Invalid Table role Permissions. A valid List JSON representation is expected.')
@@ -280,12 +280,152 @@ def validate_table_role_definition_body(cmd, ns):
280280

281281
ns.table_role_definition_body = table_role_definition
282282

283+
283284
def validate_table_role_definition_id(ns):
284285
""" Extracts Guid role definition Id """
285286
if ns.role_definition_id is not None:
286287
ns.role_definition_id = _parse_resource_path(ns.role_definition_id, False, "tableRoleDefinitions")
287-
288+
289+
288290
def validate_table_role_assignment_id(ns):
289291
""" Extracts Guid role assignment Id """
290292
if ns.role_assignment_id is not None:
291-
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "tableRoleAssignments")
293+
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "tableRoleAssignments")
294+
295+
296+
def validate_gremlin_role_definition_body(cmd, ns):
297+
""" Extracts role definition body """
298+
from azext_cosmosdb_preview.vendored_sdks.azure_mgmt_cosmosdb.models import RoleDefinitionType
299+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
300+
import os
301+
302+
if ns.gremlin_role_definition_body is not None:
303+
if os.path.exists(ns.gremlin_role_definition_body):
304+
gremlin_role_definition = get_file_json(ns.gremlin_role_definition_body)
305+
else:
306+
gremlin_role_definition = shell_safe_json_parse(ns.gremlin_role_definition_body)
307+
308+
if not isinstance(gremlin_role_definition, dict):
309+
raise InvalidArgumentValueError(
310+
'Role creation failed. Invalid gremlin role definition. A valid dictionary JSON representation is expected.')
311+
312+
if 'RoleName' not in gremlin_role_definition or not isinstance(gremlin_role_definition['RoleName'], str) or len(gremlin_role_definition['RoleName']) == 0:
313+
raise InvalidArgumentValueError(
314+
'Role creation failed. Invalid gremlin role name. A valid string role name is expected.')
315+
316+
if 'AssignableScopes' not in gremlin_role_definition or not isinstance(gremlin_role_definition['AssignableScopes'], list) or len(gremlin_role_definition['AssignableScopes']) == 0:
317+
raise InvalidArgumentValueError(
318+
'Role creation failed. Invalid Gremlin role definition for AssignableScopes. A valid list of strings is expected.')
319+
320+
if 'Permissions' not in gremlin_role_definition or not isinstance(gremlin_role_definition['Permissions'], list) or len(gremlin_role_definition['Permissions']) == 0:
321+
raise InvalidArgumentValueError(
322+
'Role creation failed. Invalid Gremlin role Permissions. A valid List JSON representation is expected.')
323+
324+
if 'Type' not in gremlin_role_definition:
325+
gremlin_role_definition['Type'] = RoleDefinitionType.custom_role
326+
327+
ns.gremlin_role_definition_body = gremlin_role_definition
328+
329+
330+
def validate_gremlin_role_definition_id(ns):
331+
""" Extracts Guid role definition Id """
332+
if ns.role_definition_id is not None:
333+
ns.role_definition_id = _parse_resource_path(ns.role_definition_id, False, "gremlinRoleDefinitions")
334+
335+
336+
def validate_gremlin_role_assignment_id(ns):
337+
""" Extracts Guid role assignment Id """
338+
if ns.role_assignment_id is not None:
339+
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "gremlinRoleAssignments")
340+
341+
342+
def validate_cassandra_role_definition_body(cmd, ns):
343+
""" Extracts role definition body """
344+
from azext_cosmosdb_preview.vendored_sdks.azure_mgmt_cosmosdb.models import RoleDefinitionType
345+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
346+
import os
347+
348+
if ns.cassandra_role_definition_body is not None:
349+
if os.path.exists(ns.cassandra_role_definition_body):
350+
cassandra_role_definition = get_file_json(ns.cassandra_role_definition_body)
351+
else:
352+
cassandra_role_definition = shell_safe_json_parse(ns.cassandra_role_definition_body)
353+
354+
if not isinstance(cassandra_role_definition, dict):
355+
raise InvalidArgumentValueError(
356+
'Role creation failed. Invalid cassandra role definition. A valid dictionary JSON representation is expected.')
357+
358+
if 'RoleName' not in cassandra_role_definition or not isinstance(cassandra_role_definition['RoleName'], str) or len(cassandra_role_definition['RoleName']) == 0:
359+
raise InvalidArgumentValueError(
360+
'Role creation failed. Invalid cassandra role name. A valid string role name is expected.')
361+
362+
if 'AssignableScopes' not in cassandra_role_definition or not isinstance(cassandra_role_definition['AssignableScopes'], list) or len(cassandra_role_definition['AssignableScopes']) == 0:
363+
raise InvalidArgumentValueError(
364+
'Role creation failed. Invalid Cassandra role definition for AssignableScopes. A valid list of strings is expected.')
365+
366+
if 'Permissions' not in cassandra_role_definition or not isinstance(cassandra_role_definition['Permissions'], list) or len(cassandra_role_definition['Permissions']) == 0:
367+
raise InvalidArgumentValueError(
368+
'Role creation failed. Invalid Cassandra role Permissions. A valid List JSON representation is expected.')
369+
370+
if 'Type' not in cassandra_role_definition:
371+
cassandra_role_definition['Type'] = RoleDefinitionType.custom_role
372+
373+
ns.cassandra_role_definition_body = cassandra_role_definition
374+
375+
376+
def validate_cassandra_role_definition_id(ns):
377+
""" Extracts Guid role definition Id """
378+
if ns.role_definition_id is not None:
379+
ns.role_definition_id = _parse_resource_path(ns.role_definition_id, False, "cassandraRoleDefinitions")
380+
381+
382+
def validate_cassandra_role_assignment_id(ns):
383+
""" Extracts Guid role assignment Id """
384+
if ns.role_assignment_id is not None:
385+
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "cassandraRoleAssignments")
386+
387+
388+
def validate_mongoMI_role_definition_body(cmd, ns):
389+
""" Extracts role definition body """
390+
from azext_cosmosdb_preview.vendored_sdks.azure_mgmt_cosmosdb.models import RoleDefinitionType
391+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
392+
import os
393+
394+
if ns.mongoMI_role_definition_body is not None:
395+
if os.path.exists(ns.mongoMI_role_definition_body):
396+
mongoMI_role_definition = get_file_json(ns.mongoMI_role_definition_body)
397+
else:
398+
mongoMI_role_definition = shell_safe_json_parse(ns.mongoMI_role_definition_body)
399+
400+
if not isinstance(mongoMI_role_definition, dict):
401+
raise InvalidArgumentValueError(
402+
'Role creation failed. Invalid mongoMI role definition. A valid dictionary JSON representation is expected.')
403+
404+
if 'RoleName' not in mongoMI_role_definition or not isinstance(mongoMI_role_definition['RoleName'], str) or len(mongoMI_role_definition['RoleName']) == 0:
405+
raise InvalidArgumentValueError(
406+
'Role creation failed. Invalid mongoMI role name. A valid string role name is expected.')
407+
408+
if 'AssignableScopes' not in mongoMI_role_definition or not isinstance(mongoMI_role_definition['AssignableScopes'], list) or len(mongoMI_role_definition['AssignableScopes']) == 0:
409+
raise InvalidArgumentValueError(
410+
'Role creation failed. Invalid MongoMI role definition for AssignableScopes. A valid list of strings is expected.')
411+
412+
if 'Permissions' not in mongoMI_role_definition or not isinstance(mongoMI_role_definition['Permissions'], list) or len(mongoMI_role_definition['Permissions']) == 0:
413+
raise InvalidArgumentValueError(
414+
'Role creation failed. Invalid MongoMI role Permissions. A valid List JSON representation is expected.')
415+
416+
if 'Type' not in mongoMI_role_definition:
417+
mongoMI_role_definition['Type'] = RoleDefinitionType.custom_role
418+
419+
ns.mongoMI_role_definition_body = mongoMI_role_definition
420+
421+
422+
def validate_mongoMI_role_definition_id(ns):
423+
""" Extracts Guid role definition Id """
424+
if ns.role_definition_id is not None:
425+
ns.role_definition_id = _parse_resource_path(ns.role_definition_id, False, "mongoMIRoleDefinitions")
426+
427+
428+
def validate_mongoMI_role_assignment_id(ns):
429+
""" Extracts Guid role assignment Id """
430+
if ns.role_assignment_id is not None:
431+
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "mongoMIRoleAssignments")

0 commit comments

Comments
 (0)