Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _build_arguments_schema(cls, *args, **kwargs):

_args_schema = cls._args_schema
_args_schema.admin_password = AAZPasswordArg(
options=["-p", "--admin-password"],
options=["-p", "--password", "--admin-password"],
arg_group="Administrator",
help="The administrator password.",
required=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _build_arguments_schema(cls, *args, **kwargs):

_args_schema = cls._args_schema
_args_schema.admin_password = AAZPasswordArg(
options=["-p", "--admin-password"],
options=["-p", "--password", "--admin-password"],
arg_group="Administrator",
help="The administrator password.",
nullable=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Delete(AAZCommand):
"""Delete a mongo cluster user.

:example: Delete a user.
az documentdb mongocluster user delete -n alice@contoso.com --cluster-name MyCluster -g MyResourceGroup
az documentdb mongocluster user delete -n alice-entra --cluster-name MyCluster -g MyResourceGroup
"""

_aaz_info = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
"documentdb mongocluster user show",
)
class Show(AAZCommand):
"""Get the defintion of a Mongo cluster user.
"""Get the definition of a Mongo cluster user.

:example: Get a user.
az documentdb mongocluster user show -n alice@contoso.com --cluster-name MyCluster -g MyResourceGroup
az documentdb mongocluster user show -n alice-entra --cluster-name MyCluster -g MyResourceGroup
Comment thread
amatarritamicrosoft marked this conversation as resolved.
Outdated
"""

_aaz_info = {
Expand Down
3 changes: 2 additions & 1 deletion src/documentdb/azext_documentdb/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@

def load_command_table(self, _): # pylint: disable=unused-argument
from azext_documentdb.custom import (
UserCreate, UserUpdate, ResetPassword, ReplicaCreate, Restore)
UserCreate, UserUpdate, ResetPassword, ReplicaCreate, Restore, ReplicaPromote)
self.command_table['documentdb mongocluster user create'] = UserCreate(loader=self)
self.command_table['documentdb mongocluster user update'] = UserUpdate(loader=self)
self.command_table['documentdb mongocluster reset-password'] = ResetPassword(loader=self)
self.command_table['documentdb mongocluster replica create'] = ReplicaCreate(loader=self)
self.command_table['documentdb mongocluster replica promote'] = ReplicaPromote(loader=self)
self.command_table['documentdb mongocluster restore'] = Restore(loader=self)
75 changes: 71 additions & 4 deletions src/documentdb/azext_documentdb/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from azext_documentdb.aaz.latest.documentdb.mongocluster import Update as _MongoClusterUpdate
from azext_documentdb.aaz.latest.documentdb.mongocluster.user import Create as _UserCreate
from azext_documentdb.aaz.latest.documentdb.mongocluster.user import Update as _UserUpdate
from azext_documentdb.aaz.latest.documentdb.mongocluster.replica import Promote as _ReplicaPromote

logger = get_logger(__name__)

Expand All @@ -38,13 +39,19 @@ def _resolve_cluster_id(ctx, name_or_id):
def _keep_only_args(args_schema, keep):
"""Deregister (hide) every argument on the schema except those in ``keep``.

Hidden arguments are also marked optional so a deregistered-but-required
argument (for example the base ``create`` password on a replica) does not
fail schema validation with a missing-required-field error.

Framework arguments that are not resource properties (for example ``no_wait``
and ``subscription``) are always preserved.
"""
_always_keep = {"no_wait", "subscription"}
for _name in list(args_schema._fields):
if _name not in keep and _name not in _always_keep:
args_schema._fields[_name]._registered = False
_field = args_schema._fields[_name]
_field._registered = False
_field._required = False


def _add_principal_type_arg(args_schema):
Expand Down Expand Up @@ -99,7 +106,7 @@ class ResetPassword(_MongoClusterUpdate):
"""Reset the administrator password of a mongo cluster.

:example: Reset the administrator password.
az documentdb mongocluster reset-password -n MyCluster -g MyResourceGroup --password NewP@ssw0rd123!
az documentdb mongocluster reset-password -n MyCluster -g MyResourceGroup --admin-password NewP@ssw0rd123!
"""

# Own schema caches so the deregister/rename below never mutate the shared
Expand All @@ -114,9 +121,9 @@ def _build_arguments_schema(cls, *args, **kwargs):
args_schema = super()._build_arguments_schema(*args, **kwargs)
_keep_only_args(args_schema, {"cluster_name", "resource_group", "admin_password"})
password = args_schema.admin_password
password._options = ["--password", "-p"]
password._options = ["--admin-password", "--password", "-p"]
password._required = True
password._help["name"] = "--password -p"
password._help["name"] = "--admin-password --password -p"
password._help["short-summary"] = "The new administrator password."
return args_schema

Expand Down Expand Up @@ -275,3 +282,63 @@ def content(self):
"pointInTimeUTC", AAZStrType, ".restore_time")

return self.serialize_content(_content_value)


class ReplicaPromote(_ReplicaPromote):
"""Promote a replica mongo cluster to a primary role.

:example: Promote a replica to primary.
az documentdb mongocluster replica promote -n MyReplica -g MyResourceGroup --mode Switchover --promote-option Forced
"""

# ``promote`` already exists as a generated command, so this wrapper only
# needs to override the request body. It is swapped in over the generated
# command through ``commands.py`` (which runs after the generated table is
# loaded), exactly like the ``user create``/``user update`` overrides, so it
# deliberately does not re-register the command name.
class MongoClustersPromote(_ReplicaPromote.MongoClustersPromote):

def __call__(self, *args, **kwargs):
# The generated operation passes ``None`` as the long-running
# operation's final-result callback, so azure-core raises
# ``TypeError: 'NoneType' object is not callable`` when the promote
# completes and it tries to parse the final resource. The promote
# returns no body, so pass a no-op callback (``on_200``) instead,
# mirroring how the generated ``delete`` handles its empty response.
request = self.make_request()
session = self.client.send_request(request=request, stream=False, **kwargs)
if session.http_response.status_code in [202]:
return self.client.build_lro_polling(
self.ctx.args.no_wait,
session,
self.on_200,
self.on_error,
lro_options={"final-state-via": "location"},
path_format_arguments=self.url_parameters,
)
return self.on_error(session.http_response)

def on_200(self, session):
pass

@property
def content(self):
# The service expects the promote payload nested under "properties",
# but the generated command sends "mode"/"promoteOption" at the root,
# which the service rejects with a schema error. Wrap them here.
_content_value, _builder = self.new_content_builder(
self.ctx.args,
typ=AAZObjectType,
typ_kwargs={"flags": {"required": True, "client_flatten": True}},
)
_builder.set_prop(
"properties", AAZObjectType, typ_kwargs={"flags": {"required": True}})

properties = _builder.get(".properties")
if properties is not None:
properties.set_prop("mode", AAZStrType, ".mode")
properties.set_prop(
"promoteOption", AAZStrType, ".promote_option",
typ_kwargs={"flags": {"required": True}})

return self.serialize_content(_content_value)
Loading
Loading