Skip to content

Commit f003d56

Browse files
[cosmosdb-preview] Add support for Fleet/Fleetspace/FleetspaceAccount/FleetAnalytics CRUD actions (#8803)
* Added latest python SDK * Fleet and Fleetspace New commands * Fleet and Fleetspace commands fixes * FleetspaceAccount commands and tests * Fleet analytics commands * fix issues * fixed tests recordings * Fixed rest of tests --------- Co-authored-by: Praful Johari <pjohari@microsoft.com>
1 parent 891e2cd commit f003d56

File tree

74 files changed

+39569
-21956
lines changed

Some content is hidden

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

74 files changed

+39569
-21956
lines changed

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.6.0
5+
* Add support for Fleet/Fleetspace/FleetspaceAccount/FleetAnalytics CRUD actions.
6+
7+
+++++++
48
1.5.0
59
* Add support for Gremlin/Cassandra/Mongo RBAC role definition and assignment CRUD actions.
610

src/cosmosdb-preview/azext_cosmosdb_preview/_client_factory.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,20 @@ def cf_mongo_clusters(cli_ctx, _):
102102

103103
def cf_mongo_cluster_firewall_rules(cli_ctx, _):
104104
return cf_mongocluster_preview(cli_ctx).firewall_rules
105+
106+
107+
# fleet
108+
def cf_fleet(cli_ctx, _):
109+
return cf_cosmosdb_preview(cli_ctx).fleet
110+
111+
112+
def cf_fleetspace(cli_ctx, _):
113+
return cf_cosmosdb_preview(cli_ctx).fleetspace
114+
115+
116+
def cf_fleetspace_account(cli_ctx, _):
117+
return cf_cosmosdb_preview(cli_ctx).fleetspace_account
118+
119+
120+
def cf_fleet_analytics(cli_ctx, _):
121+
return cf_cosmosdb_preview(cli_ctx).fleet_analytics

src/cosmosdb-preview/azext_cosmosdb_preview/_help.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,3 +1699,148 @@
16991699
--scope "/dbs/mydb/colls/mycontainer" \\
17001700
--principal-id 6328f5f7-dbf7-4244-bba8-fbb9d8066506
17011701
"""
1702+
1703+
helps['cosmosdb fleet'] = """
1704+
type: group
1705+
short-summary: Manage Azure Cosmos DB Fleet resources.
1706+
"""
1707+
1708+
helps['cosmosdb fleet create'] = """
1709+
type: command
1710+
short-summary: Create a new Cosmos DB Fleet.
1711+
examples:
1712+
- name: Create a fleet
1713+
text: |
1714+
az cosmosdb fleet create \\
1715+
--resource-group MyResourceGroup \\
1716+
--fleet-name MyFleet \\
1717+
--location westus
1718+
"""
1719+
1720+
helps['cosmosdb fleet list'] = """
1721+
type: command
1722+
short-summary: List Cosmos DB Fleets in a subscription or resource group.
1723+
"""
1724+
1725+
helps['cosmosdb fleet show'] = """
1726+
type: command
1727+
short-summary: Show details of a specific Cosmos DB Fleet.
1728+
"""
1729+
1730+
helps['cosmosdb fleet delete'] = """
1731+
type: command
1732+
short-summary: Delete a specific Cosmos DB Fleet.
1733+
"""
1734+
1735+
helps['cosmosdb fleetspace'] = """
1736+
type: group
1737+
short-summary: Manage Cosmos DB Fleetspace resources.
1738+
"""
1739+
1740+
helps['cosmosdb fleetspace create'] = """
1741+
type: command
1742+
short-summary: Create a new Fleetspace under a Cosmos DB Fleet.
1743+
examples:
1744+
- name: Create a fleetspace
1745+
text: |
1746+
az cosmosdb fleetspace create \\
1747+
--resource-group MyResourceGroup \\
1748+
--fleet-name MyFleet \\
1749+
--fleetspace-name MyFleetspace \\
1750+
--body @fleetspace.json
1751+
"""
1752+
1753+
helps['cosmosdb fleetspace update'] = """
1754+
type: command
1755+
short-summary: Update an existing Cosmos DB Fleetspace.
1756+
examples:
1757+
- name: Update fleetspace throughput settings
1758+
text: |
1759+
az cosmosdb fleetspace update \\
1760+
--resource-group MyResourceGroup \\
1761+
--fleet-name MyFleet \\
1762+
--fleetspace-name MyFleetspace \\
1763+
--body @fleetspace.json
1764+
"""
1765+
1766+
helps['cosmosdb fleetspace list'] = """
1767+
type: command
1768+
short-summary: List all Fleetspaces under a Fleet.
1769+
"""
1770+
1771+
helps['cosmosdb fleetspace show'] = """
1772+
type: command
1773+
short-summary: Show details of a specific Fleetspace.
1774+
"""
1775+
1776+
helps['cosmosdb fleetspace delete'] = """
1777+
type: command
1778+
short-summary: Delete a Fleetspace from a Fleet.
1779+
"""
1780+
1781+
helps['cosmosdb fleetspace account'] = """
1782+
type: group
1783+
short-summary: Manage database accounts within a Cosmos DB Fleetspace.
1784+
"""
1785+
1786+
helps['cosmosdb fleetspace account create'] = """
1787+
type: command
1788+
short-summary: Register an existing Cosmos DB database account to a Fleetspace.
1789+
examples:
1790+
- name: Register a database account to a fleetspace
1791+
text: |
1792+
az cosmosdb fleetspace account create \\
1793+
--resource-group MyResourceGroup \\
1794+
--fleet-name MyFleet \\
1795+
--fleetspace-name MyFleetspace \\
1796+
--fleetspace-account-name MyAccount \\
1797+
--body @fleetspaceAccount.json
1798+
"""
1799+
1800+
helps['cosmosdb fleetspace account list'] = """
1801+
type: command
1802+
short-summary: List all database accounts associated with a Fleetspace.
1803+
"""
1804+
1805+
helps['cosmosdb fleetspace account show'] = """
1806+
type: command
1807+
short-summary: Show details of a registered database account in a Fleetspace.
1808+
"""
1809+
1810+
helps['cosmosdb fleetspace account delete'] = """
1811+
type: command
1812+
short-summary: Unregister a database account from a Fleetspace.
1813+
"""
1814+
1815+
helps['cosmosdb fleet analytics'] = """
1816+
type: group
1817+
short-summary: Manage Azure Cosmos DB Fleet Analytics resources.
1818+
"""
1819+
1820+
helps['cosmosdb fleet analytics create'] = """
1821+
type: command
1822+
short-summary: Create a new Fleet Analytics resource under a Cosmos DB Fleet.
1823+
examples:
1824+
- name: Create a Fleet Analytics resource
1825+
text: |
1826+
az cosmosdb fleet analytics create \\
1827+
--resource-group MyResourceGroup \\
1828+
--fleet-name MyFleet \\
1829+
--fleet-analytics-name MyFleetAnalytics \\
1830+
--body @fleetAnalytics.json
1831+
"""
1832+
1833+
helps['cosmosdb fleet analytics show'] = """
1834+
type: command
1835+
short-summary: Show details of a specific Fleet Analytics resource.
1836+
"""
1837+
1838+
helps['cosmosdb fleet analytics list'] = """
1839+
type: command
1840+
short-summary: List all Fleet Analytics resources under a Fleet.
1841+
"""
1842+
1843+
helps['cosmosdb fleet analytics delete'] = """
1844+
type: command
1845+
short-summary: Delete a Fleet Analytics resource from a Fleet.
1846+
"""

src/cosmosdb-preview/azext_cosmosdb_preview/_params.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@
2929
validate_cassandra_role_assignment_id,
3030
validate_mongoMI_role_definition_body,
3131
validate_mongoMI_role_definition_id,
32-
validate_mongoMI_role_assignment_id)
32+
validate_mongoMI_role_assignment_id,
33+
validate_fleetspace_body,
34+
validate_fleetspaceAccount_body,
35+
validate_fleet_analytics_body)
3336

3437
from azext_cosmosdb_preview.actions import (
3538
CreateGremlinDatabaseRestoreResource,
@@ -196,6 +199,37 @@
196199
"""
197200

198201

202+
FLEETSPACE_PROPERTIES_EXAMPLE = """--body "{
203+
\\"properties\\": {
204+
\\"throughputPoolConfiguration\\": {
205+
\\"minThroughput\\": 100000,
206+
\\"maxThroughput\\": 300000,
207+
\\"serviceTier\\": \\"GeneralPurpose\\",
208+
\\"dataRegions\\": [\\"West US 2\\"]
209+
},
210+
}
211+
}"
212+
"""
213+
214+
FLEETSPACE_ACCOUNT_PROPERTIES_EXAMPLE = """--body "{
215+
\\"properties\\": {
216+
\\"globalDatabaseAccountProperties\\": {
217+
\\"resourceId\\": \\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.DocumentDB/databaseAccounts/example-account\\",
218+
\\"armLocation\\": \\"East US\\"
219+
}
220+
}
221+
}"
222+
"""
223+
224+
FLEET_ANALYTICS_PROPERTIES_EXAMPLE = """--body "{
225+
\\"properties\\": {
226+
\\"storageLocationType\\": \\"StorageAccount\\",
227+
\\"storageLocationUri\\": \\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Storage/storageAccounts/exampleaccount\\"
228+
}
229+
}"
230+
"""
231+
232+
199233
class ThroughputTypes(str, Enum):
200234
autoscale = "autoscale"
201235
manual = "manual"
@@ -794,3 +828,43 @@ def load_arguments(self, _):
794828
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'.")
795829
c.argument('scope', options_list=['--scope', '-s'], help="Data plane resource path at which this Role Assignment is being granted.")
796830
c.argument('principal_id', options_list=['--principal-id', '-p'], help="AAD Object ID of the principal to which this Role Assignment is being granted.")
831+
832+
# Cosmos DB Fleet
833+
with self.argument_context('cosmosdb fleet') as c:
834+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
835+
c.argument('fleet_name', options_list=['--fleet-name', '-n'], help='Name of the Fleet resource.', required=True)
836+
837+
with self.argument_context('cosmosdb fleet create') as c:
838+
c.argument('location', options_list=['--location', '-l'], help='Location of the Fleet.', required=True)
839+
c.argument('tags', help="Tags in 'key=value key2=value2' format.")
840+
841+
# Cosmos DB Fleet Analytics
842+
with self.argument_context('cosmosdb fleet analytics') as c:
843+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
844+
c.argument('fleet_name', options_list=['--fleet-name'], help='Name of the Cosmos DB Fleet.', required=True)
845+
c.argument('fleet_analytics_name', options_list=['--fleet-analytics-name', '-n'], help='Name of the Fleet Analytics resource.', required=True)
846+
847+
with self.argument_context('cosmosdb fleet analytics create') as c:
848+
c.argument('fleet_analytics_body', options_list=['--body', '-b'], validator=validate_fleet_analytics_body, completer=FilesCompleter(), help="Fleet Analytics body with properties (fields: storageLocationType, storageLocationUri). You can enter it as a string or as a file, e.g., --body @fleetAnalytics.json or " + FLEET_ANALYTICS_PROPERTIES_EXAMPLE)
849+
850+
# Cosmos DB Fleetspace
851+
with self.argument_context('cosmosdb fleetspace') as c:
852+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
853+
c.argument('fleet_name', options_list=['--fleet-name'], help='Name of the Cosmos DB Fleet.', required=True)
854+
c.argument('fleetspace_name', options_list=['--fleetspace-name', '-n'], help='Name of the Fleetspace resource.', required=True)
855+
856+
with self.argument_context('cosmosdb fleetspace create') as c:
857+
c.argument('fleetspace_body', options_list=['--body', '-b'], validator=validate_fleetspace_body, completer=FilesCompleter(), help="Fleetspace body with properties.throughputPoolConfiguration (fields: minThroughput, maxThroughput, serviceTier, dataRegions). You can enter it as a string or as a file, e.g., --body @fleetspace.json or " + FLEETSPACE_PROPERTIES_EXAMPLE)
858+
859+
with self.argument_context('cosmosdb fleetspace update') as c:
860+
c.argument('fleetspace_body', options_list=['--body', '-b'], validator=validate_fleetspace_body, completer=FilesCompleter(), help="Fleetspace body with properties.throughputPoolConfiguration (fields: minThroughput, maxThroughput, serviceTier, dataRegions). You can enter it as a string or as a file, e.g., --body @fleetspace.json or " + FLEETSPACE_PROPERTIES_EXAMPLE)
861+
862+
# Cosmos DB Fleetspace account
863+
with self.argument_context('cosmosdb fleetspace account') as c:
864+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
865+
c.argument('fleet_name', options_list=['--fleet-name'], help='Name of the Cosmos DB Fleet.', required=True)
866+
c.argument('fleetspace_name', options_list=['--fleetspace-name'], help='Name of the Fleetspace resource.', required=True)
867+
c.argument('fleetspace_account_name', options_list=['--fleetspace-account-name', '-n'], help='Name of the Fleetspace Account resource.', required=True)
868+
869+
with self.argument_context('cosmosdb fleetspace account create') as c:
870+
c.argument('fleetspace_account_body', options_list=['--body', '-b'], validator=validate_fleetspaceAccount_body, completer=FilesCompleter(), help="Fleetspace Account body with properties.globalDatabaseAccountProperties (fields: armLocation, resourceId). You can enter it as a string or as a file, e.g., --body @fleetspaceAccount.json or " + FLEETSPACE_ACCOUNT_PROPERTIES_EXAMPLE)

src/cosmosdb-preview/azext_cosmosdb_preview/_validators.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,101 @@ def validate_mongoMI_role_assignment_id(ns):
429429
""" Extracts Guid role assignment Id """
430430
if ns.role_assignment_id is not None:
431431
ns.role_assignment_id = _parse_resource_path(ns.role_assignment_id, False, "mongoMIRoleAssignments")
432+
433+
434+
def validate_fleetspace_body(cmd, ns):
435+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
436+
import os
437+
438+
if ns.fleetspace_body is not None:
439+
if os.path.exists(ns.fleetspace_body):
440+
body = get_file_json(ns.fleetspace_body)
441+
else:
442+
body = shell_safe_json_parse(ns.fleetspace_body)
443+
444+
if not isinstance(body, dict):
445+
raise InvalidArgumentValueError('Invalid fleetspace body. Must be a JSON object.')
446+
447+
props = body.get('properties', {})
448+
if not isinstance(props, dict):
449+
raise InvalidArgumentValueError('Missing or invalid "properties" field in fleetspace body.')
450+
451+
tp_config = props.get('throughputPoolConfiguration', {})
452+
if not isinstance(tp_config, dict):
453+
raise InvalidArgumentValueError('Missing or invalid "throughputPoolConfiguration" in properties.')
454+
455+
for field in ['minThroughput', 'maxThroughput', 'serviceTier', 'dataRegions']:
456+
if field not in tp_config:
457+
raise InvalidArgumentValueError(f'Missing "{field}" in throughputPoolConfiguration.')
458+
459+
if not isinstance(tp_config['minThroughput'], int) or tp_config['minThroughput'] <= 0:
460+
raise InvalidArgumentValueError('"minThroughput" must be a positive integer.')
461+
462+
if not isinstance(tp_config['maxThroughput'], int) or tp_config['maxThroughput'] <= 0:
463+
raise InvalidArgumentValueError('"maxThroughput" must be a positive integer.')
464+
465+
if not isinstance(tp_config['serviceTier'], str):
466+
raise InvalidArgumentValueError('"serviceTier" must be a string.')
467+
468+
if not isinstance(tp_config['dataRegions'], list) or not all(isinstance(r, str) for r in tp_config['dataRegions']):
469+
raise InvalidArgumentValueError('"dataRegions" must be a list of strings.')
470+
471+
ns.fleetspace_body = body
472+
473+
474+
def validate_fleet_analytics_body(cmd, ns):
475+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
476+
import os
477+
478+
if ns.fleet_analytics_body is not None:
479+
if os.path.exists(ns.fleet_analytics_body):
480+
body = get_file_json(ns.fleet_analytics_body)
481+
else:
482+
body = shell_safe_json_parse(ns.fleet_analytics_body)
483+
484+
if not isinstance(body, dict):
485+
raise InvalidArgumentValueError('Fleet Analytics body must be a valid JSON object.')
486+
487+
props = body.get("properties")
488+
if not isinstance(props, dict):
489+
raise InvalidArgumentValueError('Missing or invalid "properties" field.')
490+
491+
slt = props.get("storageLocationType")
492+
if slt not in ["StorageAccount", "FabricLakehouse"]:
493+
raise InvalidArgumentValueError('"storageLocationType" must be "StorageAccount" or "FabricLakehouse".')
494+
495+
slu = props.get("storageLocationUri")
496+
if not isinstance(slu, str) or not slu.strip():
497+
raise InvalidArgumentValueError('"storageLocationUri" must be a non-empty string.')
498+
499+
ns.fleet_analytics_body = body
500+
501+
502+
def validate_fleetspaceAccount_body(cmd, ns):
503+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
504+
import os
505+
506+
if ns.fleetspace_account_body is not None:
507+
if os.path.exists(ns.fleetspace_account_body):
508+
body = get_file_json(ns.fleetspace_account_body)
509+
else:
510+
body = shell_safe_json_parse(ns.fleetspace_account_body)
511+
512+
if not isinstance(body, dict):
513+
raise InvalidArgumentValueError("Fleetspace Account body must be a valid JSON object.")
514+
515+
props = body.get("properties")
516+
if not isinstance(props, dict):
517+
raise InvalidArgumentValueError('Missing or invalid "properties" field.')
518+
519+
gdp = props.get("globalDatabaseAccountProperties")
520+
if not isinstance(gdp, dict):
521+
raise InvalidArgumentValueError('Missing or invalid "globalDatabaseAccountProperties".')
522+
523+
if "resourceId" not in gdp or not isinstance(gdp["resourceId"], str) or not gdp["resourceId"].startswith("/subscriptions/"):
524+
raise InvalidArgumentValueError('"resourceId" must be a valid ARM resource ID string.')
525+
526+
if "armLocation" not in gdp or not isinstance(gdp["armLocation"], str):
527+
raise InvalidArgumentValueError('"armLocation" must be a valid string.')
528+
529+
ns.fleetspace_account_body = body

0 commit comments

Comments
 (0)