Skip to content

Commit ad66d3b

Browse files
pjohari-msdsapaligaAchint-Agrawal
authored
[CosmosDB] az cosmosdb fleet: Add new fleet feature (#32390)
Co-authored-by: Darshan Sapaliga <[email protected]> Co-authored-by: Achint Agrawal <[email protected]>
1 parent 1d853bd commit ad66d3b

File tree

99 files changed

+43904
-40811
lines changed

Some content is hidden

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

99 files changed

+43904
-40811
lines changed

src/azure-cli/azure/cli/command_modules/cosmosdb/_client_factory.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,16 @@ def cf_restorable_tables(cli_ctx, _):
174174

175175
def cf_restorable_table_resources(cli_ctx, _):
176176
return cf_cosmosdb(cli_ctx).restorable_table_resources
177+
178+
179+
# fleet
180+
def cf_fleet(cli_ctx, _):
181+
return cf_cosmosdb(cli_ctx).fleet
182+
183+
184+
def cf_fleetspace(cli_ctx, _):
185+
return cf_cosmosdb(cli_ctx).fleetspace
186+
187+
188+
def cf_fleetspace_account(cli_ctx, _):
189+
return cf_cosmosdb(cli_ctx).fleetspace_account

src/azure-cli/azure/cli/command_modules/cosmosdb/_help.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,3 +1785,115 @@
17851785
text: |
17861786
az cosmosdb table restore --resource-group resource_group --account-name database_account_name --table-name name_of_table_needs_to_be_restored --restore-timestamp 2020-07-13T16:03:41+0000
17871787
"""
1788+
1789+
helps['cosmosdb fleet'] = """
1790+
type: group
1791+
short-summary: Manage Azure Cosmos DB Fleet resources.
1792+
"""
1793+
1794+
helps['cosmosdb fleet create'] = """
1795+
type: command
1796+
short-summary: Create a new Cosmos DB Fleet.
1797+
examples:
1798+
- name: Create a fleet
1799+
text: |
1800+
az cosmosdb fleet create \\
1801+
--resource-group MyResourceGroup \\
1802+
--fleet-name MyFleet \\
1803+
--location westus
1804+
"""
1805+
1806+
helps['cosmosdb fleet list'] = """
1807+
type: command
1808+
short-summary: List Cosmos DB Fleets in a subscription or resource group.
1809+
"""
1810+
1811+
helps['cosmosdb fleet show'] = """
1812+
type: command
1813+
short-summary: Show details of a specific Cosmos DB Fleet.
1814+
"""
1815+
1816+
helps['cosmosdb fleet delete'] = """
1817+
type: command
1818+
short-summary: Delete a specific Cosmos DB Fleet.
1819+
"""
1820+
1821+
helps['cosmosdb fleetspace'] = """
1822+
type: group
1823+
short-summary: Manage Cosmos DB Fleetspace resources.
1824+
"""
1825+
1826+
helps['cosmosdb fleetspace create'] = """
1827+
type: command
1828+
short-summary: Create a new Fleetspace under a Cosmos DB Fleet.
1829+
examples:
1830+
- name: Create a fleetspace
1831+
text: |
1832+
az cosmosdb fleetspace create \\
1833+
--resource-group MyResourceGroup \\
1834+
--fleet-name MyFleet \\
1835+
--fleetspace-name MyFleetspace \\
1836+
--body @fleetspace.json
1837+
"""
1838+
1839+
helps['cosmosdb fleetspace update'] = """
1840+
type: command
1841+
short-summary: Update an existing Cosmos DB Fleetspace.
1842+
examples:
1843+
- name: Update fleetspace throughput settings
1844+
text: |
1845+
az cosmosdb fleetspace update \\
1846+
--resource-group MyResourceGroup \\
1847+
--fleet-name MyFleet \\
1848+
--fleetspace-name MyFleetspace \\
1849+
--body @fleetspace.json
1850+
"""
1851+
1852+
helps['cosmosdb fleetspace list'] = """
1853+
type: command
1854+
short-summary: List all Fleetspaces under a Fleet.
1855+
"""
1856+
1857+
helps['cosmosdb fleetspace show'] = """
1858+
type: command
1859+
short-summary: Show details of a specific Fleetspace.
1860+
"""
1861+
1862+
helps['cosmosdb fleetspace delete'] = """
1863+
type: command
1864+
short-summary: Delete a Fleetspace from a Fleet.
1865+
"""
1866+
1867+
helps['cosmosdb fleetspace account'] = """
1868+
type: group
1869+
short-summary: Manage database accounts within a Cosmos DB Fleetspace.
1870+
"""
1871+
1872+
helps['cosmosdb fleetspace account create'] = """
1873+
type: command
1874+
short-summary: Register an existing Cosmos DB database account to a Fleetspace.
1875+
examples:
1876+
- name: Register a database account to a fleetspace
1877+
text: |
1878+
az cosmosdb fleetspace account create \\
1879+
--resource-group MyResourceGroup \\
1880+
--fleet-name MyFleet \\
1881+
--fleetspace-name MyFleetspace \\
1882+
--fleetspace-account-name MyAccount \\
1883+
--body @fleetspaceAccount.json
1884+
"""
1885+
1886+
helps['cosmosdb fleetspace account list'] = """
1887+
type: command
1888+
short-summary: List all database accounts associated with a Fleetspace.
1889+
"""
1890+
1891+
helps['cosmosdb fleetspace account show'] = """
1892+
type: command
1893+
short-summary: Show details of a registered database account in a Fleetspace.
1894+
"""
1895+
1896+
helps['cosmosdb fleetspace account delete'] = """
1897+
type: command
1898+
short-summary: Unregister a database account from a Fleetspace.
1899+
"""

src/azure-cli/azure/cli/command_modules/cosmosdb/_params.py

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@
2828
validate_mongo_role_definition_body,
2929
validate_mongo_role_definition_id,
3030
validate_mongo_user_definition_body,
31-
validate_mongo_user_definition_id)
31+
validate_mongo_user_definition_id,
32+
validate_fleetspace_body,
33+
validate_fleetspaceAccount_body)
3234

3335
from azure.cli.command_modules.cosmosdb.actions import (
3436
CreateLocation, CreateDatabaseRestoreResource, CreateGremlinDatabaseRestoreResource, CreateTableRestoreResource, UtcDatetimeAction, InvokeCommandArgumentsAddAction)
3537
from azure.cli.command_modules.cosmosdb.custom import (
3638
CosmosKeyTypes)
3739
from azure.mgmt.cosmosdb.models import (
38-
ContinuousTier, MinimalTlsVersion)
40+
ContinuousTier, MinimalTlsVersion, DefaultPriorityLevel)
3941

4042
GREMLIN_INDEXING_POLICY_EXAMPLE = """--idx "{\\"indexingMode\\": \\"consistent\\", \\"automatic\\": true, \\"includedPaths\\": [{\\"path\\": \\"/*\\"}], \\"excludedPaths\\": [{ \\"path\\": \\"/headquarters/employees/?\\"}, { \\"path\\": \\"/\\\\"_etag\\\\"/?\\"}]}"
4143
"""
@@ -72,6 +74,28 @@
7274
MONGO_USER_DEFINITION_EXAMPLE = """--body "{\\"Id\\": \\"be79875a-2cc4-40d5-8958-566017875b39\\",\\"UserName\\": \\"MyUserName\\",\\"Password\\": \\"MyPass\\",\\"CustomData\\": \\"MyCustomData\\",\\"Mechanisms\\": \\"SCRAM-SHA-256\\"\\"DatabaseName\\": \\"MyDb\\",\\"Roles\\": [ {\\"Role\\": \\"myReadRole\\",\\"Db\\": \\"MyDb\\"}]}"
7375
"""
7476

77+
FLEETSPACE_PROPERTIES_EXAMPLE = """--body "{
78+
\\"properties\\": {
79+
\\"serviceTier\\": \\"GeneralPurpose\\",
80+
\\"dataRegions\\": [\\"West US 2\\"],
81+
\\"throughputPoolConfiguration\\": {
82+
\\"minThroughput\\": 100000,
83+
\\"maxThroughput\\": 300000
84+
}
85+
}
86+
}"
87+
"""
88+
89+
FLEETSPACE_ACCOUNT_PROPERTIES_EXAMPLE = """--body "{
90+
\\"properties\\": {
91+
\\"globalDatabaseAccountProperties\\": {
92+
\\"resourceId\\": \\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.DocumentDB/databaseAccounts/example-account\\",
93+
\\"armLocation\\": \\"East US\\"
94+
}
95+
}
96+
}"
97+
"""
98+
7599

76100
class ThroughputTypes(str, Enum):
77101
autoscale = "autoscale"
@@ -131,6 +155,8 @@ def load_arguments(self, _):
131155
c.argument('enable_partition_merge', arg_type=get_three_state_flag(), help="Flag to enable partition merge on the account.")
132156
c.argument('enable_burst_capacity', arg_type=get_three_state_flag(), help="Flag to enable burst capacity on the account.")
133157
c.argument('enable_prpp_autoscale', arg_type=get_three_state_flag(), help="Enable or disable PerRegionPerPartitionAutoscale.")
158+
c.argument('enable_pbe', arg_type=get_three_state_flag(), help="Flag to enable priority based execution on the account.")
159+
c.argument('default_priority_level', arg_type=get_enum_type(DefaultPriorityLevel), help="Default Priority Level of Request if not specified.")
134160
c.argument('continuous_tier', arg_type=get_enum_type(ContinuousTier), help="The tier of Continuous backup", arg_group='Backup Policy')
135161
c.argument('minimal_tls_version', arg_type=get_enum_type(MinimalTlsVersion), help="Indicates the minimum allowed TLS version")
136162

@@ -407,14 +433,15 @@ def load_arguments(self, _):
407433
c.argument('target_database_account_name', options_list=['--target-database-account-name', '-n'], help='Name of the new target Cosmos DB database account after the restore')
408434
c.argument('account_name', completer=None, options_list=['--account-name', '-a'], help='Name of the source Cosmos DB database account for the restore', id_part=None)
409435
c.argument('restore_timestamp', options_list=['--restore-timestamp', '-t'], action=UtcDatetimeAction, help="The timestamp to which the account has to be restored to.")
410-
c.argument('location', arg_type=get_location_type(self.cli_ctx), help="The location of the source account from which restore is triggered. This will also be the write region of the restored account")
436+
c.argument('location', arg_type=get_location_type(self.cli_ctx), help="This is the write region of the restored account. This is also the location of the source account where its backups are located if source_backup_location is not provided.")
411437
c.argument('databases_to_restore', nargs='+', action=CreateDatabaseRestoreResource)
412438
c.argument('gremlin_databases_to_restore', nargs='+', action=CreateGremlinDatabaseRestoreResource)
413439
c.argument('tables_to_restore', nargs='+', action=CreateTableRestoreResource)
414440
c.argument('assign_identity', nargs='*', help="Assign system or user assigned identities separated by spaces. Use '[system]' to refer system assigned identity.")
415441
c.argument('default_identity', help="The primary identity to access key vault in CMK related features. e.g. 'FirstPartyIdentity', 'SystemAssignedIdentity' and more.")
416442
c.argument('public_network_access', options_list=['--public-network-access', '-p'], arg_type=get_enum_type(['ENABLED', 'DISABLED']), help="Sets public network access in server to either Enabled or Disabled.")
417443
c.argument('disable_ttl', options_list=['--disable-ttl', '-d'], arg_type=get_three_state_flag(), help="Enable or disable restoring with ttl disabled.")
444+
c.argument('source_backup_location', help="This is the location of the source account where backups are located. Provide this value if the source and target are in different locations.", is_preview=True)
418445

419446
# Mongo role definition
420447
with self.argument_context('cosmosdb mongodb role definition') as c:
@@ -681,3 +708,34 @@ def load_arguments(self, _):
681708
c.argument('instance_count', options_list=['--count', '-c'], help="Instance Count.")
682709
c.argument('instance_size', options_list=['--size'], help="Instance Size. Possible values are: Cosmos.D4s, Cosmos.D8s, Cosmos.D16s etc")
683710
c.argument('dedicated_gateway_type', options_list=['--gateway-type'], arg_type=get_enum_type(['IntegratedCache', 'DistributedQuery']), help="Dedicated Gateway Type. Valid only for SqlDedicatedGateway service kind")
711+
712+
# Cosmos DB Fleet
713+
with self.argument_context('cosmosdb fleet') as c:
714+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
715+
c.argument('fleet_name', options_list=['--fleet-name', '-n'], help='Name of the Fleet resource.', required=True)
716+
717+
with self.argument_context('cosmosdb fleet create') as c:
718+
c.argument('location', options_list=['--location', '-l'], help='Location of the Fleet.', required=True)
719+
c.argument('tags', help="Tags in 'key=value key2=value2' format.")
720+
721+
# Cosmos DB Fleetspace
722+
with self.argument_context('cosmosdb fleetspace') as c:
723+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
724+
c.argument('fleet_name', options_list=['--fleet-name'], help='Name of the Cosmos DB Fleet.', required=True)
725+
c.argument('fleetspace_name', options_list=['--fleetspace-name', '-n'], help='Name of the Fleetspace resource.', required=True)
726+
727+
with self.argument_context('cosmosdb fleetspace create') as c:
728+
c.argument('fleetspace_body', options_list=['--body', '-b'], validator=validate_fleetspace_body, completer=FilesCompleter(), help="Fleetspace body with properties.serviceTier (required), properties.dataRegions (required), and properties.throughputPoolConfiguration (fields: minThroughput, maxThroughput). You can enter it as a string or as a file, e.g., --body @fleetspace.json or " + FLEETSPACE_PROPERTIES_EXAMPLE)
729+
730+
with self.argument_context('cosmosdb fleetspace update') as c:
731+
c.argument('fleetspace_body', options_list=['--body', '-b'], validator=validate_fleetspace_body, completer=FilesCompleter(), help="Fleetspace body with properties.serviceTier (optional), properties.dataRegions (optional), and properties.throughputPoolConfiguration (fields: minThroughput, maxThroughput). You can enter it as a string or as a file, e.g., --body @fleetspace.json or " + FLEETSPACE_PROPERTIES_EXAMPLE)
732+
733+
# Cosmos DB Fleetspace account
734+
with self.argument_context('cosmosdb fleetspace account') as c:
735+
c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of the resource group.', required=True)
736+
c.argument('fleet_name', options_list=['--fleet-name'], help='Name of the Cosmos DB Fleet.', required=True)
737+
c.argument('fleetspace_name', options_list=['--fleetspace-name'], help='Name of the Fleetspace resource.', required=True)
738+
c.argument('fleetspace_account_name', options_list=['--fleetspace-account-name', '-n'], help='Name of the Fleetspace Account resource.', required=True)
739+
740+
with self.argument_context('cosmosdb fleetspace account create') as c:
741+
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/azure-cli/azure/cli/command_modules/cosmosdb/_validators.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,77 @@ def _validate_pk_paths_in_cep(path, partition_key_path, policyFormatVersion, enc
531531
raise InvalidArgumentValueError(f"Partition key path:{pkPath} is part of "
532532
"Client Encryption policy with invalid encryption type. "
533533
"Only deterministic encryption type is supported.")
534+
535+
536+
def validate_fleetspace_body(cmd, ns):
537+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
538+
import os
539+
540+
if ns.fleetspace_body is not None:
541+
if os.path.exists(ns.fleetspace_body):
542+
body = get_file_json(ns.fleetspace_body)
543+
else:
544+
body = shell_safe_json_parse(ns.fleetspace_body)
545+
546+
if not isinstance(body, dict):
547+
raise InvalidArgumentValueError('Invalid fleetspace body. Must be a JSON object.')
548+
549+
props = body.get('properties', {})
550+
if not isinstance(props, dict):
551+
raise InvalidArgumentValueError('Missing or invalid "properties" field in fleetspace body.')
552+
553+
tp_config = props.get('throughputPoolConfiguration', {})
554+
if not isinstance(tp_config, dict):
555+
raise InvalidArgumentValueError('Missing or invalid "throughputPoolConfiguration" in properties.')
556+
557+
# Check for minThroughput and maxThroughput in throughputPoolConfiguration
558+
for field in ['minThroughput', 'maxThroughput']:
559+
if field not in tp_config:
560+
raise InvalidArgumentValueError(f'Missing "{field}" in throughputPoolConfiguration.')
561+
562+
if not isinstance(tp_config['minThroughput'], int) or tp_config['minThroughput'] <= 0:
563+
raise InvalidArgumentValueError('"minThroughput" must be a positive integer.')
564+
565+
if not isinstance(tp_config['maxThroughput'], int) or tp_config['maxThroughput'] <= 0:
566+
raise InvalidArgumentValueError('"maxThroughput" must be a positive integer.')
567+
568+
# Check for serviceTier and dataRegions at base properties level
569+
if 'serviceTier' in props:
570+
if not isinstance(props['serviceTier'], str):
571+
raise InvalidArgumentValueError('"serviceTier" must be a string.')
572+
573+
if 'dataRegions' in props:
574+
if not isinstance(props['dataRegions'], list) or not all(isinstance(r, str) for r in props['dataRegions']):
575+
raise InvalidArgumentValueError('"dataRegions" must be a list of strings.')
576+
577+
ns.fleetspace_body = body
578+
579+
580+
def validate_fleetspaceAccount_body(cmd, ns):
581+
from azure.cli.core.util import get_file_json, shell_safe_json_parse
582+
import os
583+
584+
if ns.fleetspace_account_body is not None:
585+
if os.path.exists(ns.fleetspace_account_body):
586+
body = get_file_json(ns.fleetspace_account_body)
587+
else:
588+
body = shell_safe_json_parse(ns.fleetspace_account_body)
589+
590+
if not isinstance(body, dict):
591+
raise InvalidArgumentValueError("Fleetspace Account body must be a valid JSON object.")
592+
593+
props = body.get("properties")
594+
if not isinstance(props, dict):
595+
raise InvalidArgumentValueError('Missing or invalid "properties" field.')
596+
597+
gdp = props.get("globalDatabaseAccountProperties")
598+
if not isinstance(gdp, dict):
599+
raise InvalidArgumentValueError('Missing or invalid "globalDatabaseAccountProperties".')
600+
601+
if "resourceId" not in gdp or not isinstance(gdp["resourceId"], str) or not gdp["resourceId"].startswith("/subscriptions/"):
602+
raise InvalidArgumentValueError('"resourceId" must be a valid ARM resource ID string.')
603+
604+
if "armLocation" not in gdp or not isinstance(gdp["armLocation"], str):
605+
raise InvalidArgumentValueError('"armLocation" must be a valid string.')
606+
607+
ns.fleetspace_account_body = body

src/azure-cli/azure/cli/command_modules/cosmosdb/commands.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
cf_db_locations,
3333
cf_cassandra_cluster,
3434
cf_cassandra_data_center,
35-
cf_service
35+
cf_service,
36+
cf_fleet,
37+
cf_fleetspace,
38+
cf_fleetspace_account
3639
)
3740

3841
from azure.cli.command_modules.cosmosdb._format import (
@@ -499,3 +502,41 @@ def load_command_table(self, _):
499502
g.command('list', 'list')
500503
g.show_command('show', 'get')
501504
g.command('delete', 'begin_delete', confirmation=True, supports_no_wait=True)
505+
506+
setup_fleet_commands(self)
507+
508+
509+
def setup_fleet_commands(self):
510+
# Fleet operations
511+
cosmosdb_fleet_sdk = CliCommandType(
512+
operations_tmpl='azure.mgmt.cosmosdb.operations#FleetOperations.{}',
513+
client_factory=cf_fleet)
514+
515+
# Fleetspace operations
516+
cosmosdb_fleetspace_sdk = CliCommandType(
517+
operations_tmpl='azure.mgmt.cosmosdb.operations#FleetspaceOperations.{}',
518+
client_factory=cf_fleetspace)
519+
520+
# Fleetspace account operations
521+
cosmosdb_fleetspace_account_sdk = CliCommandType(
522+
operations_tmpl='azure.mgmt.cosmosdb.operations#FleetspaceAccountOperations.{}',
523+
client_factory=cf_fleetspace_account)
524+
525+
with self.command_group('cosmosdb fleet', cosmosdb_fleet_sdk, client_factory=cf_fleet, is_preview=True) as g:
526+
g.custom_command('create', 'cli_cosmosdb_fleet_create')
527+
g.custom_command('list', 'cli_list_cosmosdb_fleets')
528+
g.show_command('show', 'get')
529+
g.command('delete', 'begin_delete', confirmation=True)
530+
531+
with self.command_group('cosmosdb fleetspace', cosmosdb_fleetspace_sdk, client_factory=cf_fleetspace, is_preview=True) as g:
532+
g.custom_command('create', 'cli_cosmosdb_fleetspace_create')
533+
g.command('list', 'list')
534+
g.show_command('show', 'get')
535+
g.custom_command('update', 'cli_cosmosdb_fleetspace_update')
536+
g.command('delete', 'begin_delete', confirmation=True)
537+
538+
with self.command_group('cosmosdb fleetspace account', cosmosdb_fleetspace_account_sdk, client_factory=cf_fleetspace_account, is_preview=True) as g:
539+
g.custom_command('create', 'cli_cosmosdb_fleetspace_account_create')
540+
g.command('list', 'list')
541+
g.show_command('show', 'get')
542+
g.command('delete', 'begin_delete', confirmation=True)

0 commit comments

Comments
 (0)