Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions src/multicloud-connector/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Release History
===============
1.1.0
++++++
* Target the ``2027-01-01`` GA version of the Microsoft.HybridConnectivity API
* Add GCP support to ``public-cloud-connector create`` and ``public-cloud-connector update`` via ``--gcp-cloud-profile``
* Support ``GCP`` as a value of ``--host-type``
* Add ``generate-gcp-template`` command to retrieve the GCP access control template
* Surface the read-only ``kind`` property on public cloud connectors and ``hostTypes`` on solution types

1.0.1
++++++
* Update help message for better readability
Expand Down
10 changes: 10 additions & 0 deletions src/multicloud-connector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ This is an extension to Azure CLI to manage MulticloudConnector resources.
arc-multicloud generate-aws-template --connector-id pnxcfjidglabnwxit --solution-types "[{solution-type:hjyownzpfxwiufmd,solution-settings:{}}]"
```

- Create a PublicCloudConnector for GCP
```bash
arc-multicloud public-cloud-connector create --resource-group rgpublicCloud --name gcpConnector --gcp-cloud-profile "{project-properties:{project-number:123456789123,project-id:my-project},organization-properties:{organization-id:123456789123,management-project-number:123456789124,management-project-id:my-management-project}}" --host-type GCP --tags "{}" --location eastus
```

- GenerateGcpTemplate
```bash
arc-multicloud generate-gcp-template --connector-id pnxcfjidglabnwxit --gcp-template-format terraform --solution-types "[{solution-type:hjyownzpfxwiufmd,solution-settings:{}}]"
```

- Test allowed permissions of a PublicCloudConnector
```bash
arc-multicloud public-cloud-connector test-permission --resource-group rgpublicCloud --name sjuahmnojgachluzcbhxhwkxwugbsi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@

from .__cmd_group import *
from ._generate_aws_template import *
from ._generate_gcp_template import *
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class GenerateAwsTemplate(AAZCommand):
"""

_aaz_info = {
"version": "2024-12-01",
"version": "2027-01-01",
"resources": [
["mgmt-plane", "/subscriptions/{}/providers/microsoft.hybridconnectivity/generateawstemplate", "2024-12-01"],
["mgmt-plane", "/subscriptions/{}/providers/microsoft.hybridconnectivity/generateawstemplate", "2027-01-01"],
]
}

Expand Down Expand Up @@ -113,7 +113,7 @@ def url_parameters(self):
def query_parameters(self):
parameters = {
**self.serialize_query_param(
"api-version", "2024-12-01",
"api-version", "2027-01-01",
required=True,
),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
# --------------------------------------------------------------------------------------------
# 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(
"arc-multicloud generate-gcp-template",
)
class GenerateGcpTemplate(AAZCommand):
"""Retrieve GCP access control template

For additional details, please visit the https://learn.microsoft.com/en-us/cli/azure/arc-multicloud?view=azure-cli-latest

:example: GenerateGcpTemplate_Post
az arc-multicloud generate-gcp-template --connector-id /subscriptions/{}/resourceGroups/{}/providers/Microsoft.HybridConnectivity/publicCloudConnectors/{} --output-directory example_folder/templates

:example: GenerateGcpTemplate_Post
az arc-multicloud generate-gcp-template --connector-id /subscriptions/{}/resourceGroups/{}/providers/Microsoft.HybridConnectivity/publicCloudConnectors/{} --gcp-template-format shellscript --gcp-cloud-profile "{project-properties:{project-number:1234567890,project-id:my-project},organization-properties:{organization-id:123456789,management-project-number:1234567890,management-project-id:my-project}}"

:example: GenerateGcpTemplate_Post
az arc-multicloud generate-gcp-template --connector-id /subscriptions/{}/resourceGroups/{}/providers/Microsoft.HybridConnectivity/publicCloudConnectors/{} --gcp-template-format shellscript --gcp-cloud-profile project-properties.project-number=1234567890 project-properties.project-id=my-project organization-properties.organization-id=123456789 organization-properties.management-project-number=1234567890 organization-properties.management-project-id=my-project
"""

_aaz_info = {
"version": "2027-01-01",
"resources": [
["mgmt-plane", "/subscriptions/{}/providers/microsoft.hybridconnectivity/generategcptemplate", "2027-01-01"],
]
}

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 ""

# define Arg Group "GenerateGcpTemplateRequest"

_args_schema = cls._args_schema
_args_schema.connector_id = AAZStrArg(
options=["--connector-id"],
arg_group="GenerateGcpTemplateRequest",
help="The fully qualified Azure Resource manager identifier of the public cloud connector",
required=True,
)
_args_schema.gcp_cloud_profile = AAZObjectArg(
options=["--gcp-cloud-profile"],
arg_group="GenerateGcpTemplateRequest",
help="The GCP cloud profile.",
)
_args_schema.gcp_template_format = AAZStrArg(
options=["--gcp-template-format"],
arg_group="GenerateGcpTemplateRequest",
help="Optional template output format. Defaults to 'terraform' if not provided",
enum={"shellscript": "shellscript", "terraform": "terraform"},
)
_args_schema.solution_types = AAZListArg(
options=["--solution-types"],
arg_group="GenerateGcpTemplateRequest",
help="The list of solution types and their settings",
)

gcp_cloud_profile = cls._args_schema.gcp_cloud_profile
gcp_cloud_profile.organization_properties = AAZObjectArg(
options=["organization-properties"],
help="The organization properties of the GCP organization.",
)
gcp_cloud_profile.project_properties = AAZObjectArg(
options=["project-properties"],
help="The project properties of the GCP project.",
)

organization_properties = cls._args_schema.gcp_cloud_profile.organization_properties
organization_properties.excluded_folder_ids = AAZListArg(
options=["excluded-folder-ids"],
help="List of GCP folders which need to be excluded.",
)
organization_properties.excluded_project_numbers = AAZListArg(
options=["excluded-project-numbers"],
help="List of GCP projects which need to be excluded.",
)
organization_properties.management_project_id = AAZStrArg(
options=["management-project-id"],
help="The project Id of the management project under the GCP organization.",
required=True,
)
organization_properties.management_project_number = AAZStrArg(
options=["management-project-number"],
help="The project number of the management project under the GCP organization.",
required=True,
)
organization_properties.organization_id = AAZStrArg(
options=["organization-id"],
help="The organization id of the GCP organization.",
required=True,
)

excluded_folder_ids = cls._args_schema.gcp_cloud_profile.organization_properties.excluded_folder_ids
excluded_folder_ids.Element = AAZStrArg()

excluded_project_numbers = cls._args_schema.gcp_cloud_profile.organization_properties.excluded_project_numbers
excluded_project_numbers.Element = AAZStrArg()

project_properties = cls._args_schema.gcp_cloud_profile.project_properties
project_properties.project_id = AAZStrArg(
options=["project-id"],
help="The project id of the GCP project.",
required=True,
)
project_properties.project_number = AAZStrArg(
options=["project-number"],
help="The project number of the GCP project.",
required=True,
)

solution_types = cls._args_schema.solution_types
solution_types.Element = AAZObjectArg()

_element = cls._args_schema.solution_types.Element
_element.solution_settings = AAZDictArg(
options=["solution-settings"],
help="Solution settings",
)
_element.solution_type = AAZStrArg(
options=["solution-type"],
help="The type of the solution",
required=True,
)

solution_settings = cls._args_schema.solution_types.Element.solution_settings
solution_settings.Element = AAZStrArg()
return cls._args_schema

def _execute_operations(self):
self.pre_operations()
self.GenerateGcpTemplatePost(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 GenerateGcpTemplatePost(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(
"/subscriptions/{subscriptionId}/providers/Microsoft.HybridConnectivity/generateGcpTemplate",
**self.url_parameters
)

@property
def method(self):
return "POST"

@property
def error_format(self):
return "MgmtErrorFormat"

@property
def url_parameters(self):
parameters = {
**self.serialize_url_param(
"subscriptionId", self.ctx.subscription_id,
required=True,
),
}
return parameters

@property
def query_parameters(self):
parameters = {
**self.serialize_query_param(
"api-version", "2027-01-01",
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("connectorId", AAZStrType, ".connector_id", typ_kwargs={"flags": {"required": True}})
_builder.set_prop("gcpCloudProfile", AAZObjectType, ".gcp_cloud_profile")
_builder.set_prop("gcpTemplateFormat", AAZStrType, ".gcp_template_format")
_builder.set_prop("solutionTypes", AAZListType, ".solution_types")

gcp_cloud_profile = _builder.get(".gcpCloudProfile")
if gcp_cloud_profile is not None:
gcp_cloud_profile.set_prop("organizationProperties", AAZObjectType, ".organization_properties")
gcp_cloud_profile.set_prop("projectProperties", AAZObjectType, ".project_properties")

organization_properties = _builder.get(".gcpCloudProfile.organizationProperties")
if organization_properties is not None:
organization_properties.set_prop("excludedFolderIds", AAZListType, ".excluded_folder_ids")
organization_properties.set_prop("excludedProjectNumbers", AAZListType, ".excluded_project_numbers")
organization_properties.set_prop("managementProjectId", AAZStrType, ".management_project_id", typ_kwargs={"flags": {"required": True}})
organization_properties.set_prop("managementProjectNumber", AAZStrType, ".management_project_number", typ_kwargs={"flags": {"required": True}})
organization_properties.set_prop("organizationId", AAZStrType, ".organization_id", typ_kwargs={"flags": {"required": True}})

excluded_folder_ids = _builder.get(".gcpCloudProfile.organizationProperties.excludedFolderIds")
if excluded_folder_ids is not None:
excluded_folder_ids.set_elements(AAZStrType, ".")

excluded_project_numbers = _builder.get(".gcpCloudProfile.organizationProperties.excludedProjectNumbers")
if excluded_project_numbers is not None:
excluded_project_numbers.set_elements(AAZStrType, ".")

project_properties = _builder.get(".gcpCloudProfile.projectProperties")
if project_properties is not None:
project_properties.set_prop("projectId", AAZStrType, ".project_id", typ_kwargs={"flags": {"required": True}})
project_properties.set_prop("projectNumber", AAZStrType, ".project_number", typ_kwargs={"flags": {"required": True}})

solution_types = _builder.get(".solutionTypes")
if solution_types is not None:
solution_types.set_elements(AAZObjectType, ".")

_elements = _builder.get(".solutionTypes[]")
if _elements is not None:
_elements.set_prop("solutionSettings", AAZDictType, ".solution_settings")
_elements.set_prop("solutionType", AAZStrType, ".solution_type", typ_kwargs={"flags": {"required": True}})

solution_settings = _builder.get(".solutionTypes[].solutionSettings")
if solution_settings is not None:
solution_settings.set_elements(AAZStrType, ".")

return self.serialize_content(_content_value)

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 = AAZFreeFormDictType()

return cls._schema_on_200


class _GenerateGcpTemplateHelper:
"""Helper class for GenerateGcpTemplate"""


__all__ = ["GenerateGcpTemplate"]
Loading
Loading