Skip to content

[DONT MERGE] [DONT REVIEW] [AKS] identity binding commands #8724

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def cf_machines(cli_ctx, *_):
return get_container_service_client(cli_ctx).machines


def cf_identity_bindings(cli_ctx, *_):
return get_container_service_client(cli_ctx).identity_bindings


def cf_operations(cli_ctx, *_):
return get_container_service_client(cli_ctx).operation_status_result

Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# `az aks identity-binding create` command
def aks_ib_cmd_create(
cmd, client,
resource_group_name: str,
cluster_name: str,
name: str,
managed_identity_resource_id: str,
no_wait: bool = False,
):
from azure.mgmt.core.tools import parse_resource_id
from azure.cli.core.util import sdk_no_wait
from azext_aks_preview._client_factory import get_msi_client
from azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.models import (
IdentityBinding,
IdentityBindingProperties,
IdentityBindingManagedIdentityProfile,
)

# FIXME(hbc): workaround for resolving MI from client side
parsed_managed_identity_resource_id = parse_resource_id(managed_identity_resource_id)
msi_client = get_msi_client(cmd.cli_ctx, subscription_id=parsed_managed_identity_resource_id['subscription'])
msi = msi_client.user_assigned_identities.get(
parsed_managed_identity_resource_id['resource_group'],
parsed_managed_identity_resource_id['resource_name'],
)

instance = IdentityBinding(
name=name,
properties=IdentityBindingProperties(
managed_identity=IdentityBindingManagedIdentityProfile(
resource_id=managed_identity_resource_id,
client_id=msi.client_id,
object_id=msi.principal_id,
tenant_id=msi.tenant_id,
)
)
)
instance.name = name
print(instance)

return sdk_no_wait(
no_wait,
client.begin_create_or_update,
resource_group_name,
cluster_name,
name,
instance,
)

# `az aks identity-binding delete` command
def aks_ib_cmd_delete(
cmd, client,
resource_group_name: str,
cluster_name: str,
name: str,
no_wait: bool = False,
):
from azure.cli.core.util import sdk_no_wait

return sdk_no_wait(
no_wait,
client.begin_delete,
resource_group_name=resource_group_name,
resource_name=cluster_name,
identity_binding_name=name,
)


# `az aks identity-binding show` command
def aks_ib_cmd_show(
cmd, client,
resource_group_name: str,
cluster_name: str,
name: str,
):
return client.get(
resource_group_name=resource_group_name,
resource_name=cluster_name,
identity_binding_name=name,
)


# `az aks identity-binding list` command
def aks_ib_cmd_list(
cmd, client,
resource_group_name: str,
cluster_name: str,
):
return client.list_by_managed_cluster(
resource_group_name=resource_group_name,
resource_name=cluster_name,
)
10 changes: 10 additions & 0 deletions src/aks-preview/azext_aks_preview/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
cf_machines,
cf_operations,
cf_load_balancers,
cf_identity_bindings,
)
from azext_aks_preview._format import (
aks_addon_list_available_table_format,
Expand Down Expand Up @@ -430,3 +431,12 @@ def load_command_table(self, _):
"aks check-network", managed_clusters_sdk, client_factory=cf_managed_clusters
) as g:
g.custom_command("outbound", "aks_check_network_outbound")

# AKS identity binding commands
with self.command_group(
"aks identity-binding", managed_clusters_sdk, client_factory=cf_identity_bindings
) as g:
g.custom_command("create", "aks_identity_binding_create")
g.custom_command("delete", "aks_identity_binding_delete")
g.custom_command("show", "aks_identity_binding_show")
g.custom_command("list", "aks_identity_binding_list")
12 changes: 12 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
from azext_aks_preview.maintenanceconfiguration import (
aks_maintenanceconfiguration_update_internal,
)
from azext_aks_preview.aks_identity_binding.commands import (
aks_ib_cmd_create,
aks_ib_cmd_delete,
aks_ib_cmd_show,
aks_ib_cmd_list,
)
from azure.cli.command_modules.acs._helpers import (
get_user_assigned_identity_by_resource_id
)
Expand Down Expand Up @@ -3821,3 +3827,9 @@ def aks_loadbalancer_rebalance_nodes(
}

return aks_loadbalancer_rebalance_internal(managed_clusters_client, parameters)


aks_identity_binding_create = aks_ib_cmd_create
aks_identity_binding_delete = aks_ib_cmd_delete
aks_identity_binding_show = aks_ib_cmd_show
aks_identity_binding_list = aks_ib_cmd_list
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ def models(cls, api_version=DEFAULT_API_VERSION):
elif api_version == '2025-02-02-preview':
from .v2025_02_02_preview import models
return models
elif api_version == '2025-04-02-preview':
from .v2025_02_02_preview import models
return models
raise ValueError("API version {} is not available".format(api_version))

@property
Expand Down Expand Up @@ -220,6 +223,17 @@ def machines(self):
self._config.api_version = api_version
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)), api_version)

@property
def identity_bindings(self):
api_version = '2025-04-02-preview'
from .v2025_02_02_preview.operations import IdentityBindingsOperations as OperationClass
return OperationClass(
self._client, self._config,
Serializer(self._models_dict(api_version)),
Deserializer(self._models_dict(api_version)),
api_version
)

@property
def maintenance_configurations(self):
"""Instance depends on the API version:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,11 @@ def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return
:return: Deserialized object.
:rtype: object
"""
# FIXME(hbc): wrong server side response content type header
if isinstance(target_obj, str) and 'IdentityBinding' in target_obj and isinstance(data, str):
import json
data = json.loads(data)

# This is already a model, go recursive just in case
if hasattr(data, "_attribute_map"):
constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")]
Expand Down Expand Up @@ -1470,6 +1475,7 @@ def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return
value = self.deserialize_data(raw_value, attr_desc["type"])
d_attrs[attr] = value
except (AttributeError, TypeError, KeyError) as err:
print(err)
msg = "Unable to deserialize to object: " + class_name # type: ignore
raise DeserializationError(msg) from err
additional_properties = self._build_additional_properties(attributes, data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .operations import (
AgentPoolsOperations,
ContainerServiceOperations,
IdentityBindingsOperations,
LoadBalancersOperations,
MachinesOperations,
MaintenanceConfigurationsOperations,
Expand Down Expand Up @@ -135,6 +136,7 @@ def __init__(
self._client: ARMPipelineClient = ARMPipelineClient(base_url=base_url, policies=_policies, **kwargs)

client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)}
print('client_models', client_models)
self._serialize = Serializer(client_models)
self._deserialize = Deserializer(client_models)
self._serialize.client_side_validation = False
Expand Down Expand Up @@ -186,6 +188,9 @@ def __init__(
self.load_balancers = LoadBalancersOperations(
self._client, self._config, self._serialize, self._deserialize, "2025-02-02-preview"
)
self.identity_bindings = IdentityBindingsOperations(
self._client, self._config, self._serialize, self._deserialize, "2025-04-02-preview"
)

def _send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: Any) -> HttpResponse:
"""Runs the network request through the client's chained policies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
GuardrailsAvailableVersionsList,
GuardrailsAvailableVersionsProperties,
IPTag,
IdentityBinding,
IdentityBindingListResult,
IdentityBindingManagedIdentityProfile,
IdentityBindingOidcIssuerProfile,
IdentityBindingProperties,
IstioCertificateAuthority,
IstioComponents,
IstioEgressGateway,
Expand Down Expand Up @@ -245,6 +250,7 @@
GPUInstanceProfile,
GuardrailsSupport,
IPFamily,
IdentityBindingProvisioningState,
IpvsScheduler,
IstioIngressGatewayMode,
KeyVaultNetworkAccessTypes,
Expand Down Expand Up @@ -347,6 +353,11 @@
"GuardrailsAvailableVersionsList",
"GuardrailsAvailableVersionsProperties",
"IPTag",
"IdentityBinding",
"IdentityBindingListResult",
"IdentityBindingManagedIdentityProfile",
"IdentityBindingOidcIssuerProfile",
"IdentityBindingProperties",
"IstioCertificateAuthority",
"IstioComponents",
"IstioEgressGateway",
Expand Down Expand Up @@ -527,6 +538,7 @@
"GPUInstanceProfile",
"GuardrailsSupport",
"IPFamily",
"IdentityBindingProvisioningState",
"IpvsScheduler",
"IstioIngressGatewayMode",
"KeyVaultNetworkAccessTypes",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,23 @@ class GuardrailsSupport(str, Enum, metaclass=CaseInsensitiveEnumMeta):
"""The version is stable and can be used on critical production clusters."""


class IdentityBindingProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta):
"""The provisioning state of the last accepted operation."""

SUCCEEDED = "Succeeded"
"""Resource has been created."""
FAILED = "Failed"
"""Resource creation failed."""
CANCELED = "Canceled"
"""Resource creation was canceled."""
CREATING = "Creating"
"""The provisioning state of an identity binding being created."""
UPDATING = "Updating"
"""The provisioning state of an identity binding being updated."""
DELETING = "Deleting"
"""The provisioning state of an identity binding being deleted."""


class IPFamily(str, Enum, metaclass=CaseInsensitiveEnumMeta):
"""To determine if address belongs IPv4 or IPv6 family."""

Expand Down
Loading
Loading