diff --git a/linter_exclusions.yml b/linter_exclusions.yml index cbe52f706c2..9a603f25ac7 100644 --- a/linter_exclusions.yml +++ b/linter_exclusions.yml @@ -3611,3 +3611,10 @@ confcom containers from_image: image: rule_exclusions: - no_positional_parameters + +relationship dependency-of create: + rule_exclusions: + - missing_command_example +relationship service-group-member create: + rule_exclusions: + - missing_command_example diff --git a/src/relationship/HISTORY.rst b/src/relationship/HISTORY.rst new file mode 100644 index 00000000000..bfa2397441e --- /dev/null +++ b/src/relationship/HISTORY.rst @@ -0,0 +1,8 @@ +.. :changelog: + +Release History +=============== + +1.0.0b1 ++++++++ +* Initial release. diff --git a/src/relationship/MANIFEST.in b/src/relationship/MANIFEST.in new file mode 100644 index 00000000000..6bdc06ae4ac --- /dev/null +++ b/src/relationship/MANIFEST.in @@ -0,0 +1,4 @@ +include README.md +include HISTORY.rst +include azext_relationship/azext_metadata.json +recursive-include azext_relationship *.py diff --git a/src/relationship/README.md b/src/relationship/README.md new file mode 100644 index 00000000000..6842606907f --- /dev/null +++ b/src/relationship/README.md @@ -0,0 +1,68 @@ +# Azure CLI Relationship Extension # +This is an extension to Azure CLI to manage Relationship resources. + +Relationships are ARM extension resources that create semantic associations +between a source resource and a target resource. Two relationship types are supported: + +- **dependencyOf** — creates dependency links between ARM resources +- **serviceGroupMember** — associates resources with Service Groups + +## How to use ## +Install this extension using the below CLI command +``` +az extension add --name relationship +``` + +### Included Features + +#### Create a dependencyOf relationship from a resource group to a service group +``` +az relationship dependency-of create \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myDependency \ + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" +``` + +#### Create a dependencyOf relationship from a subscription to a service group +``` +az relationship dependency-of create \ + --resource-uri "/subscriptions/{sub}" \ + --name subDep \ + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" +``` + +#### Show a dependencyOf relationship +``` +az relationship dependency-of show \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myDependency +``` + +#### Delete a dependencyOf relationship +``` +az relationship dependency-of delete \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myDependency --yes +``` + +#### Create a serviceGroupMember relationship +``` +az relationship service-group-member create \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myMembership \ + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" +``` + +#### Show a serviceGroupMember relationship +``` +az relationship service-group-member show \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myMembership +``` + +#### Delete a serviceGroupMember relationship +``` +az relationship service-group-member delete \ + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" \ + --name myMembership --yes +``` diff --git a/src/relationship/azext_relationship/__init__.py b/src/relationship/azext_relationship/__init__.py new file mode 100644 index 00000000000..d09039077a2 --- /dev/null +++ b/src/relationship/azext_relationship/__init__.py @@ -0,0 +1,39 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader +from azext_relationship._help import helps # pylint: disable=unused-import + + +class RelationshipCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + relationship_custom = CliCommandType( + operations_tmpl='azext_relationship.custom#{}') + super().__init__(cli_ctx=cli_ctx, custom_command_type=relationship_custom) + + def load_command_table(self, args): + from azext_relationship.commands import load_command_table + from azure.cli.core.aaz import load_aaz_command_table + try: + from . import aaz + except ImportError: + aaz = None + if aaz: + load_aaz_command_table( + loader=self, + aaz_pkg_name=aaz.__name__, + args=args + ) + load_command_table(self, args) + return self.command_table + + def load_arguments(self, command): + from azext_relationship._params import load_arguments + load_arguments(self, command) + + +COMMAND_LOADER_CLS = RelationshipCommandsLoader diff --git a/src/relationship/azext_relationship/_help.py b/src/relationship/azext_relationship/_help.py new file mode 100644 index 00000000000..130446b7d6b --- /dev/null +++ b/src/relationship/azext_relationship/_help.py @@ -0,0 +1,123 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long +# pylint: disable=too-many-lines + +from knack.help_files import helps # pylint: disable=unused-import + + +helps['relationship'] = """ + type: group + short-summary: Manage Azure Relationships. + long-summary: | + Relationships are ARM extension resources that create semantic associations between + a source resource and a target resource. Two relationship types are supported: + dependencyOf (dependency links) and serviceGroupMember (service group membership). + + NOTE: This command group is in preview and under development. +""" + +helps['relationship dependency-of'] = """ + type: group + short-summary: Manage dependencyOf relationships. + long-summary: | + DependencyOf relationships create dependency links between ARM resources. + Valid sources: Management Groups, Service Groups, Subscriptions, Resource Groups, Resources. + Valid targets: Management Groups, Service Groups, Resources. +""" + +helps['relationship dependency-of create'] = """ + type: command + short-summary: Create a dependencyOf relationship. + long-summary: Create or update a dependencyOf relationship. This is a long-running operation. + examples: + - name: Create a dependency from a resource group to a service group + text: > + az relationship dependency-of create + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myDependency + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" + - name: Create a dependency from a subscription to a service group + text: > + az relationship dependency-of create + --resource-uri "/subscriptions/{sub}" + --name subDep + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" +""" + +helps['relationship dependency-of show'] = """ + type: command + short-summary: Get the details of a dependencyOf relationship. + examples: + - name: Show a dependencyOf relationship + text: > + az relationship dependency-of show + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myDependency +""" + +helps['relationship dependency-of delete'] = """ + type: command + short-summary: Delete a dependencyOf relationship. + long-summary: Delete a dependencyOf relationship. This is a long-running operation. + examples: + - name: Delete a dependencyOf relationship + text: > + az relationship dependency-of delete + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myDependency --yes +""" + +helps['relationship service-group-member'] = """ + type: group + short-summary: Manage serviceGroupMember relationships. + long-summary: | + ServiceGroupMember relationships associate resources with Service Groups. + Valid sources: Service Groups, Subscriptions, Resource Groups, Resources. + Valid targets: Service Groups ONLY. +""" + +helps['relationship service-group-member create'] = """ + type: command + short-summary: Create a serviceGroupMember relationship. + long-summary: Create or update a serviceGroupMember relationship. This is a long-running operation. + examples: + - name: Create a service group membership from a resource group + text: > + az relationship service-group-member create + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myMembership + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" + - name: Create a service group membership from a subscription + text: > + az relationship service-group-member create + --resource-uri "/subscriptions/{sub}" + --name subMembership + --target-id "/providers/Microsoft.Management/serviceGroups/mySG" +""" + +helps['relationship service-group-member show'] = """ + type: command + short-summary: Get the details of a serviceGroupMember relationship. + examples: + - name: Show a serviceGroupMember relationship + text: > + az relationship service-group-member show + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myMembership +""" + +helps['relationship service-group-member delete'] = """ + type: command + short-summary: Delete a serviceGroupMember relationship. + long-summary: Delete a serviceGroupMember relationship. This is a long-running operation. + examples: + - name: Delete a serviceGroupMember relationship + text: > + az relationship service-group-member delete + --resource-uri "/subscriptions/{sub}/resourceGroups/{rg}" + --name myMembership --yes +""" diff --git a/src/relationship/azext_relationship/_params.py b/src/relationship/azext_relationship/_params.py new file mode 100644 index 00000000000..8cec0b34539 --- /dev/null +++ b/src/relationship/azext_relationship/_params.py @@ -0,0 +1,8 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +def load_arguments(self, _): # pylint: disable=unused-argument + pass diff --git a/src/relationship/azext_relationship/aaz/__init__.py b/src/relationship/azext_relationship/aaz/__init__.py new file mode 100644 index 00000000000..5757aea3175 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- diff --git a/src/relationship/azext_relationship/aaz/latest/__init__.py b/src/relationship/azext_relationship/aaz/latest/__init__.py new file mode 100644 index 00000000000..f6acc11aa4e --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/__init__.py @@ -0,0 +1,10 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/__cmd_group.py b/src/relationship/azext_relationship/aaz/latest/relationship/__cmd_group.py new file mode 100644 index 00000000000..839d6468426 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "relationship", +) +class __CMDGroup(AAZCommandGroup): + """Manage Relationships + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/__init__.py b/src/relationship/azext_relationship/aaz/latest/relationship/__init__.py new file mode 100644 index 00000000000..5a9d61963d6 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/__init__.py @@ -0,0 +1,11 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__cmd_group.py b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__cmd_group.py new file mode 100644 index 00000000000..f996bef768b --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "relationship dependency-of", +) +class __CMDGroup(AAZCommandGroup): + """Manage Dependency Of + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__init__.py b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__init__.py new file mode 100644 index 00000000000..45df27f97a0 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/__init__.py @@ -0,0 +1,14 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * +from ._create import * +from ._delete import * +from ._show import * diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_create.py b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_create.py new file mode 100644 index 00000000000..ead4dcd06e9 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_create.py @@ -0,0 +1,291 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship dependency-of create", +) +class Create(AAZCommand): + """Create a DependencyOfRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/dependencyof/{}", "2023-09-01-preview"], + ] + } + + AZ_SUPPORT_NO_WAIT = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_lro_poller(self._execute_operations, self._output) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of dependencyOf relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.target_id = AAZResourceIdArg( + options=["--target-id"], + arg_group="Properties", + help="The relationship target resource id.", + required=True, + ) + _args_schema.target_tenant = AAZStrArg( + options=["--target-tenant"], + arg_group="Properties", + help="The relationship target tenant id.", + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + yield self.DependencyOfRelationshipsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class DependencyOfRelationshipsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + 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_201, + self.on_error, + lro_options={"final-state-via": "azure-async-operation"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "azure-async-operation"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/dependencyOf/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _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) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("targetId", AAZStrType, ".target_id", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("targetTenant", AAZStrType, ".target_tenant") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.metadata = AAZObjectType( + flags={"read_only": True}, + ) + properties.origin_information = AAZObjectType( + serialized_name="originInformation", + flags={"read_only": True}, + ) + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.source_id = AAZStrType( + serialized_name="sourceId", + flags={"read_only": True}, + ) + properties.target_id = AAZStrType( + serialized_name="targetId", + flags={"required": True}, + ) + properties.target_tenant = AAZStrType( + serialized_name="targetTenant", + ) + + metadata = cls._schema_on_200_201.properties.metadata + metadata.source_type = AAZStrType( + serialized_name="sourceType", + flags={"read_only": True}, + ) + metadata.target_type = AAZStrType( + serialized_name="targetType", + flags={"read_only": True}, + ) + + origin_information = cls._schema_on_200_201.properties.origin_information + origin_information.discovery_engine = AAZStrType( + serialized_name="discoveryEngine", + flags={"read_only": True}, + ) + origin_information.relationship_origin_type = AAZStrType( + serialized_name="relationshipOriginType", + flags={"read_only": True}, + ) + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + +class _CreateHelper: + """Helper class for Create""" + + +__all__ = ["Create"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_delete.py b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_delete.py new file mode 100644 index 00000000000..1aca244efd1 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_delete.py @@ -0,0 +1,161 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship dependency-of delete", + confirmation="Are you sure you want to delete this relationship?", +) +class Delete(AAZCommand): + """Delete a DependencyOfRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/dependencyof/{}", "2023-09-01-preview"], + ] + } + + AZ_SUPPORT_NO_WAIT = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_lro_poller(self._execute_operations, None) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of dependencyOf relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + yield self.DependencyOfRelationshipsDelete(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + class DependencyOfRelationshipsDelete(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + 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_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [204]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_204, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/dependencyOf/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + def on_204(self, session): + pass + + def on_200_201(self, session): + pass + + +class _DeleteHelper: + """Helper class for Delete""" + + +__all__ = ["Delete"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_show.py b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_show.py new file mode 100644 index 00000000000..8bd0e33971c --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/dependency_of/_show.py @@ -0,0 +1,240 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship dependency-of show", +) +class Show(AAZCommand): + """Get a DependencyOfRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/dependencyof/{}", "2023-09-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of dependencyOf relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + self.DependencyOfRelationshipsGet(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class DependencyOfRelationshipsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/dependencyOf/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.metadata = AAZObjectType( + flags={"read_only": True}, + ) + properties.origin_information = AAZObjectType( + serialized_name="originInformation", + flags={"read_only": True}, + ) + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.source_id = AAZStrType( + serialized_name="sourceId", + flags={"read_only": True}, + ) + properties.target_id = AAZStrType( + serialized_name="targetId", + flags={"required": True}, + ) + properties.target_tenant = AAZStrType( + serialized_name="targetTenant", + ) + + metadata = cls._schema_on_200.properties.metadata + metadata.source_type = AAZStrType( + serialized_name="sourceType", + flags={"read_only": True}, + ) + metadata.target_type = AAZStrType( + serialized_name="targetType", + flags={"read_only": True}, + ) + + origin_information = cls._schema_on_200.properties.origin_information + origin_information.discovery_engine = AAZStrType( + serialized_name="discoveryEngine", + flags={"read_only": True}, + ) + origin_information.relationship_origin_type = AAZStrType( + serialized_name="relationshipOriginType", + flags={"read_only": True}, + ) + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ShowHelper: + """Helper class for Show""" + + +__all__ = ["Show"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__cmd_group.py b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__cmd_group.py new file mode 100644 index 00000000000..0ced0a64ab8 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__cmd_group.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command_group( + "relationship service-group-member", +) +class __CMDGroup(AAZCommandGroup): + """Manage Service Group Member + """ + pass + + +__all__ = ["__CMDGroup"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__init__.py b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__init__.py new file mode 100644 index 00000000000..45df27f97a0 --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/__init__.py @@ -0,0 +1,14 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from .__cmd_group import * +from ._create import * +from ._delete import * +from ._show import * diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_create.py b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_create.py new file mode 100644 index 00000000000..5c839d37dca --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_create.py @@ -0,0 +1,291 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship service-group-member create", +) +class Create(AAZCommand): + """Create a ServiceGroupMemberRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/servicegroupmember/{}", "2023-09-01-preview"], + ] + } + + AZ_SUPPORT_NO_WAIT = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_lro_poller(self._execute_operations, self._output) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of ServiceGroupMember relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + + # define Arg Group "Properties" + + _args_schema = cls._args_schema + _args_schema.target_id = AAZResourceIdArg( + options=["--target-id"], + arg_group="Properties", + help="The relationship target resource id.", + required=True, + ) + _args_schema.target_tenant = AAZStrArg( + options=["--target-tenant"], + arg_group="Properties", + help="The relationship target tenant id.", + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + yield self.ServiceGroupMemberRelationshipsCreateOrUpdate(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ServiceGroupMemberRelationshipsCreateOrUpdate(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + 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_201, + self.on_error, + lro_options={"final-state-via": "azure-async-operation"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "azure-async-operation"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/serviceGroupMember/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "PUT" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Content-Type", "application/json", + ), + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + @property + def content(self): + _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) + + properties = _builder.get(".properties") + if properties is not None: + properties.set_prop("targetId", AAZStrType, ".target_id", typ_kwargs={"flags": {"required": True}}) + properties.set_prop("targetTenant", AAZStrType, ".target_tenant") + + return self.serialize_content(_content_value) + + def on_200_201(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200_201 + ) + + _schema_on_200_201 = None + + @classmethod + def _build_schema_on_200_201(cls): + if cls._schema_on_200_201 is not None: + return cls._schema_on_200_201 + + cls._schema_on_200_201 = AAZObjectType() + + _schema_on_200_201 = cls._schema_on_200_201 + _schema_on_200_201.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200_201.properties = AAZObjectType() + _schema_on_200_201.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200_201.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200_201.properties + properties.metadata = AAZObjectType( + flags={"read_only": True}, + ) + properties.origin_information = AAZObjectType( + serialized_name="originInformation", + flags={"read_only": True}, + ) + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.source_id = AAZStrType( + serialized_name="sourceId", + flags={"read_only": True}, + ) + properties.target_id = AAZStrType( + serialized_name="targetId", + flags={"required": True}, + ) + properties.target_tenant = AAZStrType( + serialized_name="targetTenant", + ) + + metadata = cls._schema_on_200_201.properties.metadata + metadata.source_type = AAZStrType( + serialized_name="sourceType", + flags={"read_only": True}, + ) + metadata.target_type = AAZStrType( + serialized_name="targetType", + flags={"read_only": True}, + ) + + origin_information = cls._schema_on_200_201.properties.origin_information + origin_information.discovery_engine = AAZStrType( + serialized_name="discoveryEngine", + flags={"read_only": True}, + ) + origin_information.relationship_origin_type = AAZStrType( + serialized_name="relationshipOriginType", + flags={"read_only": True}, + ) + + system_data = cls._schema_on_200_201.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200_201 + + +class _CreateHelper: + """Helper class for Create""" + + +__all__ = ["Create"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_delete.py b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_delete.py new file mode 100644 index 00000000000..87cbf9a723f --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_delete.py @@ -0,0 +1,161 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship service-group-member delete", + confirmation="Are you sure you want to delete this relationship?", +) +class Delete(AAZCommand): + """Delete a ServiceGroupMemberRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/servicegroupmember/{}", "2023-09-01-preview"], + ] + } + + AZ_SUPPORT_NO_WAIT = True + + def _handler(self, command_args): + super()._handler(command_args) + return self.build_lro_poller(self._execute_operations, None) + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of ServiceGroupMember relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + yield self.ServiceGroupMemberRelationshipsDelete(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + class ServiceGroupMemberRelationshipsDelete(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + 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_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [204]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_204, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + if session.http_response.status_code in [200, 201]: + return self.client.build_lro_polling( + self.ctx.args.no_wait, + session, + self.on_200_201, + self.on_error, + lro_options={"final-state-via": "location"}, + path_format_arguments=self.url_parameters, + ) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/serviceGroupMember/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "DELETE" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + def on_204(self, session): + pass + + def on_200_201(self, session): + pass + + +class _DeleteHelper: + """Helper class for Delete""" + + +__all__ = ["Delete"] diff --git a/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_show.py b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_show.py new file mode 100644 index 00000000000..d6d3ed3a8ed --- /dev/null +++ b/src/relationship/azext_relationship/aaz/latest/relationship/service_group_member/_show.py @@ -0,0 +1,240 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# +# Code generated by aaz-dev-tools +# -------------------------------------------------------------------------------------------- + +# pylint: skip-file +# flake8: noqa + +from azure.cli.core.aaz import * + + +@register_command( + "relationship service-group-member show", +) +class Show(AAZCommand): + """Get a ServiceGroupMemberRelationship + """ + + _aaz_info = { + "version": "2023-09-01-preview", + "resources": [ + ["mgmt-plane", "/{resourceuri}/providers/microsoft.relationships/servicegroupmember/{}", "2023-09-01-preview"], + ] + } + + def _handler(self, command_args): + super()._handler(command_args) + self._execute_operations() + return self._output() + + _args_schema = None + + @classmethod + def _build_arguments_schema(cls, *args, **kwargs): + if cls._args_schema is not None: + return cls._args_schema + cls._args_schema = super()._build_arguments_schema(*args, **kwargs) + + # define Arg Group "" + + _args_schema = cls._args_schema + _args_schema.name = AAZStrArg( + options=["--name"], + help="Name of ServiceGroupMember relationship.", + required=True, + fmt=AAZStrArgFormat( + pattern="^[a-zA-Z0-9]{3,64}$", + ), + ) + _args_schema.resource_uri = AAZStrArg( + options=["--resource-uri"], + help="The fully qualified Azure Resource manager identifier of the resource.", + required=True, + ) + return cls._args_schema + + def _execute_operations(self): + self.pre_operations() + self.ServiceGroupMemberRelationshipsGet(ctx=self.ctx)() + self.post_operations() + + @register_callback + def pre_operations(self): + pass + + @register_callback + def post_operations(self): + pass + + def _output(self, *args, **kwargs): + result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True) + return result + + class ServiceGroupMemberRelationshipsGet(AAZHttpOperation): + CLIENT_TYPE = "MgmtClient" + + def __call__(self, *args, **kwargs): + request = self.make_request() + session = self.client.send_request(request=request, stream=False, **kwargs) + if session.http_response.status_code in [200]: + return self.on_200(session) + + return self.on_error(session.http_response) + + @property + def url(self): + return self.client.format_url( + "/{resourceUri}/providers/Microsoft.Relationships/serviceGroupMember/{name}", + **self.url_parameters + ) + + @property + def method(self): + return "GET" + + @property + def error_format(self): + return "MgmtErrorFormat" + + @property + def url_parameters(self): + parameters = { + **self.serialize_url_param( + "name", self.ctx.args.name, + required=True, + ), + **self.serialize_url_param( + "resourceUri", self.ctx.args.resource_uri, + skip_quote=True, + required=True, + ), + } + return parameters + + @property + def query_parameters(self): + parameters = { + **self.serialize_query_param( + "api-version", "2023-09-01-preview", + required=True, + ), + } + return parameters + + @property + def header_parameters(self): + parameters = { + **self.serialize_header_param( + "Accept", "application/json", + ), + } + return parameters + + def on_200(self, session): + data = self.deserialize_http_content(session) + self.ctx.set_var( + "instance", + data, + schema_builder=self._build_schema_on_200 + ) + + _schema_on_200 = None + + @classmethod + def _build_schema_on_200(cls): + if cls._schema_on_200 is not None: + return cls._schema_on_200 + + cls._schema_on_200 = AAZObjectType() + + _schema_on_200 = cls._schema_on_200 + _schema_on_200.id = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.name = AAZStrType( + flags={"read_only": True}, + ) + _schema_on_200.properties = AAZObjectType() + _schema_on_200.system_data = AAZObjectType( + serialized_name="systemData", + flags={"read_only": True}, + ) + _schema_on_200.type = AAZStrType( + flags={"read_only": True}, + ) + + properties = cls._schema_on_200.properties + properties.metadata = AAZObjectType( + flags={"read_only": True}, + ) + properties.origin_information = AAZObjectType( + serialized_name="originInformation", + flags={"read_only": True}, + ) + properties.provisioning_state = AAZStrType( + serialized_name="provisioningState", + flags={"read_only": True}, + ) + properties.source_id = AAZStrType( + serialized_name="sourceId", + flags={"read_only": True}, + ) + properties.target_id = AAZStrType( + serialized_name="targetId", + flags={"required": True}, + ) + properties.target_tenant = AAZStrType( + serialized_name="targetTenant", + ) + + metadata = cls._schema_on_200.properties.metadata + metadata.source_type = AAZStrType( + serialized_name="sourceType", + flags={"read_only": True}, + ) + metadata.target_type = AAZStrType( + serialized_name="targetType", + flags={"read_only": True}, + ) + + origin_information = cls._schema_on_200.properties.origin_information + origin_information.discovery_engine = AAZStrType( + serialized_name="discoveryEngine", + flags={"read_only": True}, + ) + origin_information.relationship_origin_type = AAZStrType( + serialized_name="relationshipOriginType", + flags={"read_only": True}, + ) + + system_data = cls._schema_on_200.system_data + system_data.created_at = AAZStrType( + serialized_name="createdAt", + ) + system_data.created_by = AAZStrType( + serialized_name="createdBy", + ) + system_data.created_by_type = AAZStrType( + serialized_name="createdByType", + ) + system_data.last_modified_at = AAZStrType( + serialized_name="lastModifiedAt", + ) + system_data.last_modified_by = AAZStrType( + serialized_name="lastModifiedBy", + ) + system_data.last_modified_by_type = AAZStrType( + serialized_name="lastModifiedByType", + ) + + return cls._schema_on_200 + + +class _ShowHelper: + """Helper class for Show""" + + +__all__ = ["Show"] diff --git a/src/relationship/azext_relationship/azext_metadata.json b/src/relationship/azext_relationship/azext_metadata.json new file mode 100644 index 00000000000..71889bb136b --- /dev/null +++ b/src/relationship/azext_relationship/azext_metadata.json @@ -0,0 +1,4 @@ +{ + "azext.isPreview": true, + "azext.minCliCoreVersion": "2.75.0" +} \ No newline at end of file diff --git a/src/relationship/azext_relationship/commands.py b/src/relationship/azext_relationship/commands.py new file mode 100644 index 00000000000..a7c6aa1c7e8 --- /dev/null +++ b/src/relationship/azext_relationship/commands.py @@ -0,0 +1,8 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +def load_command_table(self, _): # pylint: disable=unused-argument + pass diff --git a/src/relationship/azext_relationship/custom.py b/src/relationship/azext_relationship/custom.py new file mode 100644 index 00000000000..4e3cc4edf70 --- /dev/null +++ b/src/relationship/azext_relationship/custom.py @@ -0,0 +1,8 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import logging + +logger = logging.getLogger(__name__) diff --git a/src/relationship/azext_relationship/tests/__init__.py b/src/relationship/azext_relationship/tests/__init__.py new file mode 100644 index 00000000000..34913fb394d --- /dev/null +++ b/src/relationship/azext_relationship/tests/__init__.py @@ -0,0 +1,4 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- diff --git a/src/relationship/azext_relationship/tests/latest/__init__.py b/src/relationship/azext_relationship/tests/latest/__init__.py new file mode 100644 index 00000000000..34913fb394d --- /dev/null +++ b/src/relationship/azext_relationship/tests/latest/__init__.py @@ -0,0 +1,4 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- diff --git a/src/relationship/azext_relationship/tests/latest/test_relationship_scenario.py b/src/relationship/azext_relationship/tests/latest/test_relationship_scenario.py new file mode 100644 index 00000000000..807f5b64e5c --- /dev/null +++ b/src/relationship/azext_relationship/tests/latest/test_relationship_scenario.py @@ -0,0 +1,292 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import os +import unittest + +from azure.cli.testsdk import ( + ScenarioTest, + live_only, +) + +# Tests that target a real Service Group require AZURE_RELATIONSHIP_TEST_TARGET_SG +# to be explicitly configured in the live environment. +SDK_TESTS_SG = os.environ.get('AZURE_RELATIONSHIP_TEST_TARGET_SG') + + +class RelationshipScenarioTest(ScenarioTest): + + def setUp(self): + super().setUp() + tests_not_requiring_target_sg = { + 'test_dependency_of_same_source_target', + 'test_sgm_invalid_target', + 'test_sgm_nonexistent_sg', + } + if ( + getattr(self, 'is_live', False) + and self._testMethodName not in tests_not_requiring_target_sg + and not SDK_TESTS_SG + ): + self.skipTest( + 'Set AZURE_RELATIONSHIP_TEST_TARGET_SG to run live tests ' + 'that require a pre-existing Service Group target.' + ) + + @live_only() + def test_dependency_of_crud(self): + """Full CRUD lifecycle for a dependencyOf relationship (RG → ServiceGroup).""" + rg_name = self.create_random_name('rg-dep-', 20) + rel_name = 'deprel' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + rg_uri = f'/subscriptions/{sub_id}/resourceGroups/{rg_name}' + + self.cmd(f'az group create --name {rg_name} --location eastus') + + try: + # CREATE + self.cmd( + f'az relationship dependency-of create ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} ' + f'--target-id "{SDK_TESTS_SG}"', + checks=[ + self.check('name', rel_name), + self.check('type', 'Microsoft.Relationships/dependencyOf'), + self.exists('properties.provisioningState'), + ] + ) + + # SHOW + self.cmd( + f'az relationship dependency-of show ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name}', + checks=[ + self.check('name', rel_name), + self.check('properties.targetId', SDK_TESTS_SG), + self.exists('properties.sourceId'), + self.exists('properties.metadata.sourceType'), + self.exists('properties.metadata.targetType'), + ] + ) + + # DELETE + self.cmd( + f'az relationship dependency-of delete ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} --yes' + ) + + # VERIFY DELETE (should 404) + self.cmd( + f'az relationship dependency-of show ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name}', + expect_failure=True + ) + finally: + self.cmd(f'az group delete --name {rg_name} --yes --no-wait') + + @live_only() + def test_dependency_of_subscription_scope(self): + """DependencyOf with subscription as the source scope.""" + rel_name = 'depsub' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + sub_uri = f'/subscriptions/{sub_id}' + + try: + # CREATE + self.cmd( + f'az relationship dependency-of create ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name} ' + f'--target-id "{SDK_TESTS_SG}"', + checks=[ + self.exists('properties.provisioningState'), + ] + ) + + # SHOW + self.cmd( + f'az relationship dependency-of show ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name}', + checks=[ + self.check('name', rel_name), + self.check('properties.targetId', SDK_TESTS_SG), + ] + ) + finally: + # DELETE + self.cmd( + f'az relationship dependency-of delete ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name} --yes', + expect_failure=False + ) + + @live_only() + def test_service_group_member_crud(self): + """Full CRUD lifecycle for a serviceGroupMember relationship (RG → ServiceGroup).""" + rg_name = self.create_random_name('rg-sgm-', 20) + rel_name = 'sgmrel' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + rg_uri = f'/subscriptions/{sub_id}/resourceGroups/{rg_name}' + + self.cmd(f'az group create --name {rg_name} --location eastus') + + try: + # CREATE + self.cmd( + f'az relationship service-group-member create ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} ' + f'--target-id "{SDK_TESTS_SG}"', + checks=[ + self.check('name', rel_name), + self.check('type', 'Microsoft.Relationships/serviceGroupMember'), + self.exists('properties.provisioningState'), + ] + ) + + # SHOW + self.cmd( + f'az relationship service-group-member show ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name}', + checks=[ + self.check('name', rel_name), + self.check('properties.targetId', SDK_TESTS_SG), + self.exists('properties.metadata.targetType'), + ] + ) + + # DELETE + self.cmd( + f'az relationship service-group-member delete ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} --yes' + ) + + # VERIFY DELETE (should 404) + self.cmd( + f'az relationship service-group-member show ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name}', + expect_failure=True + ) + finally: + self.cmd(f'az group delete --name {rg_name} --yes --no-wait') + + @live_only() + def test_sgm_subscription_scope(self): + """ServiceGroupMember with subscription as the source scope.""" + rel_name = 'sgmsub' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + sub_uri = f'/subscriptions/{sub_id}' + + try: + # CREATE + self.cmd( + f'az relationship service-group-member create ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name} ' + f'--target-id "{SDK_TESTS_SG}"', + checks=[ + self.exists('properties.provisioningState'), + self.check('type', 'Microsoft.Relationships/serviceGroupMember'), + ] + ) + + # SHOW + self.cmd( + f'az relationship service-group-member show ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name}', + checks=[ + self.check('name', rel_name), + self.check('properties.targetId', SDK_TESTS_SG), + ] + ) + finally: + # DELETE + self.cmd( + f'az relationship service-group-member delete ' + f'--resource-uri "{sub_uri}" ' + f'--name {rel_name} --yes', + expect_failure=False + ) + + @live_only() + def test_dependency_of_same_source_target(self): + """DependencyOf should fail with 400 when source == target.""" + rg_name = self.create_random_name('rg-err-same-', 20) + rel_name = 'baddep' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + rg_uri = f'/subscriptions/{sub_id}/resourceGroups/{rg_name}' + + self.cmd(f'az group create --name {rg_name} --location eastus') + + try: + # CREATE with source == target should fail + self.cmd( + f'az relationship dependency-of create ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} ' + f'--target-id "{rg_uri}"', + expect_failure=True + ) + finally: + self.cmd(f'az group delete --name {rg_name} --yes --no-wait') + + @live_only() + def test_sgm_invalid_target(self): + """ServiceGroupMember should fail when target is not a Service Group.""" + rg_name = self.create_random_name('rg-err-tgt-', 20) + rel_name = 'badsgm' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + rg_uri = f'/subscriptions/{sub_id}/resourceGroups/{rg_name}' + + self.cmd(f'az group create --name {rg_name} --location eastus') + + try: + # CREATE SGM targeting a resource group (not a SG) should fail + self.cmd( + f'az relationship service-group-member create ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} ' + f'--target-id "{rg_uri}"', + expect_failure=True + ) + finally: + self.cmd(f'az group delete --name {rg_name} --yes --no-wait') + + @live_only() + def test_sgm_nonexistent_sg(self): + """ServiceGroupMember should fail when target SG does not exist.""" + rg_name = self.create_random_name('rg-err-nosg-', 20) + rel_name = 'badnosg' + self.create_random_name('', 6).replace('-', '') + sub_id = self.get_subscription_id() + rg_uri = f'/subscriptions/{sub_id}/resourceGroups/{rg_name}' + fake_sg = '/providers/Microsoft.Management/serviceGroups/nonexistentSG12345' + + self.cmd(f'az group create --name {rg_name} --location eastus') + + try: + # CREATE SGM targeting non-existent SG should fail + self.cmd( + f'az relationship service-group-member create ' + f'--resource-uri "{rg_uri}" ' + f'--name {rel_name} ' + f'--target-id "{fake_sg}"', + expect_failure=True + ) + finally: + self.cmd(f'az group delete --name {rg_name} --yes --no-wait') + + +if __name__ == '__main__': + unittest.main() diff --git a/src/relationship/setup.cfg b/src/relationship/setup.cfg new file mode 100644 index 00000000000..3c6e79cf31d --- /dev/null +++ b/src/relationship/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/src/relationship/setup.py b/src/relationship/setup.py new file mode 100644 index 00000000000..2b7f1a96d64 --- /dev/null +++ b/src/relationship/setup.py @@ -0,0 +1,50 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from codecs import open +from setuptools import setup, find_packages + + +# HISTORY.rst entry. +VERSION = '1.0.0b1' + +# The full list of classifiers is available at +# https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'License :: OSI Approved :: MIT License', +] + +DEPENDENCIES = [] + +with open('README.md', 'r', encoding='utf-8') as f: + README = f.read() +with open('HISTORY.rst', 'r', encoding='utf-8') as f: + HISTORY = f.read() + +setup( + name='relationship', + version=VERSION, + description='Microsoft Azure Command-Line Tools Relationship Extension.', + long_description=README + '\n\n' + HISTORY, + long_description_content_type='text/markdown', + license='MIT', + author='Microsoft Corporation', + author_email='azpycli@microsoft.com', + url='https://github.com/Azure/azure-cli-extensions/tree/main/src/relationship', + classifiers=CLASSIFIERS, + packages=find_packages(exclude=["tests"]), + package_data={'azext_relationship': ['azext_metadata.json']}, + install_requires=DEPENDENCIES +) diff --git a/src/service_name.json b/src/service_name.json index dce89f29446..46ba69979c1 100644 --- a/src/service_name.json +++ b/src/service_name.json @@ -534,6 +534,11 @@ "AzureServiceName": "Cache for Redis", "URL": "https://learn.microsoft.com/azure/azure-cache-for-redis" }, + { + "Command": "az relationship", + "AzureServiceName": "Azure Relationships", + "URL": "https://learn.microsoft.com/en-us/rest/api/relationships" + }, { "Command": "az remote-rendering-account", "AzureServiceName": "Mixed Reality",