Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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/fleet/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,7 @@ Release History
1.6.4
++++++
* Fix help text for `fleet list` command.

1.6.5
++++++
* create_fleet now creates a role assignment on both the agent and API server subnets when the fleet is set to privateV2 and a user-assigned MSI is used.
5 changes: 5 additions & 0 deletions src/fleet/azext_fleet/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# --------------------------------------------------------------------------------------------

from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.mgmt.msi import ManagedServiceIdentityClient
from azure.cli.core.profiles import (
CustomResourceType,
ResourceType
Expand Down Expand Up @@ -53,3 +54,7 @@ def cf_auto_upgrade_profile_operations(cli_ctx, *_):
def get_provider_client(cli_ctx):
return get_mgmt_service_client(
cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES)


def get_msi_client(cli_ctx, subscription_id=None):
return get_mgmt_service_client(cli_ctx, ManagedServiceIdentityClient, subscription_id=subscription_id)
33 changes: 22 additions & 11 deletions src/fleet/azext_fleet/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
from knack.prompting import NoTTYException, prompt_y_n
from knack.util import CLIError
from azure.cli.command_modules.acs._roleassignments import add_role_assignment
from azure.mgmt.core.tools import parse_resource_id


from azext_fleet.constants import FLEET_1P_APP_ID
from azext_fleet._client_factory import get_provider_client
from azext_fleet._client_factory import get_msi_client

logger = get_logger(__name__)

Expand Down Expand Up @@ -154,15 +156,24 @@ def _load_kubernetes_configuration(filename):
raise CLIError(f'Error parsing {filename} ({str(ex)})') from ex


def assign_network_contributor_role_to_subnet(cmd, subnet_id):
def assign_network_contributor_role_to_subnet(cmd, object_id, subnet_id):
if not add_role_assignment(cmd, 'Network Contributor', object_id, scope=subnet_id):
logger.warning("Failed to create Network Contributor role assignment on the subnet.\n"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you provide a more detailed error? Maybe even ideally to the point at which someone could copy/paste an az role assignment create command and ask their admin to run that for them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added detailed error with command

"Please ensure you have sufficient permissions to assign roles on subnet %s.", subnet_id)


def get_msi_object_id(cmd, msi_resource_id):
parsed = parse_resource_id(msi_resource_id)
subscription_id = parsed['subscription']
resource_group_name = parsed['resource_group']
msi_name = parsed['resource_name']
msi_client = get_msi_client(cmd.cli_ctx, subscription_id=subscription_id)
msi = msi_client.user_assigned_identities.get(resource_name=msi_name,
resource_group_name=resource_group_name)
return msi.principal_id


def is_rp_registered(cmd):
resource_client = get_provider_client(cmd.cli_ctx)
provider = resource_client.providers.get("Microsoft.ContainerService")

# provider registration state being is checked to ensure that the Fleet service principal is available
# to create the role assignment on the subnet
if provider.registration_state != 'Registered':
raise CLIError("The Microsoft.ContainerService resource provider is not registered."
"Run `az provider register -n Microsoft.ContainerService --wait`.")
if not add_role_assignment(cmd, 'Network Contributor', FLEET_1P_APP_ID, scope=subnet_id):
raise CLIError("failed to create role assignment for Fleet RP.\n"
f"Do you have owner permissions on the subnet {subnet_id}?\n")
return provider.registration_state == 'Registered'
4 changes: 2 additions & 2 deletions src/fleet/azext_fleet/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def load_arguments(self, _):
c.argument('tags', tags_type)
c.argument('dns_name_prefix', options_list=['--dns-name-prefix', '-p'], help='Prefix for host names that are created. If not specified, generate a host name using the managed cluster and resource group names.')
c.argument('enable_private_cluster', action='store_true', help='Whether to create the Fleet hub as a private cluster or not.')
c.argument('enable_vnet_integration', action='store_true', is_preview=True, help='Whether to enable apiserver vnet integration for the Fleet hub or not.')
c.argument('apiserver_subnet_id', validator=validate_apiserver_subnet_id, is_preview=True, help='The subnet to be used when apiserver vnet integration is enabled.')
c.argument('enable_vnet_integration', action='store_true', help='Whether to enable apiserver vnet integration for the Fleet hub or not.')
c.argument('apiserver_subnet_id', validator=validate_apiserver_subnet_id, help='The subnet to be used when apiserver vnet integration is enabled.')
c.argument('agent_subnet_id', validator=validate_agent_subnet_id, help='The ID of the subnet which the Fleet hub node will join on startup.')
c.argument('enable_managed_identity', action='store_true', help='Enable system assigned managed identity (MSI) on the Fleet resource.')
c.argument('assign_identity', validator=validate_assign_identity, help='With --enable-managed-identity, enable user assigned managed identity (MSI) on the Fleet resource by specifying the user assigned identity\'s resource Id.')
Expand Down
22 changes: 20 additions & 2 deletions src/fleet/azext_fleet/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@
from azure.cli.core.util import sdk_no_wait, get_file_json, shell_safe_json_parse

from azext_fleet._client_factory import CUSTOM_MGMT_FLEET
from azext_fleet._helpers import print_or_merge_credentials
from azext_fleet._helpers import is_rp_registered, print_or_merge_credentials
from azext_fleet._helpers import assign_network_contributor_role_to_subnet
from azext_fleet._helpers import get_msi_object_id
from azext_fleet.constants import UPGRADE_TYPE_CONTROLPLANEONLY
from azext_fleet.constants import UPGRADE_TYPE_FULL
from azext_fleet.constants import UPGRADE_TYPE_NODEIMAGEONLY
from azext_fleet.constants import UPGRADE_TYPE_ERROR_MESSAGES
from azext_fleet.constants import SUPPORTED_GATE_STATES_FILTERS
from azext_fleet.constants import SUPPORTED_GATE_STATES_PATCH
from azext_fleet.constants import FLEET_1P_APP_ID


# pylint: disable=too-many-locals
Expand Down Expand Up @@ -90,6 +92,7 @@ def create_fleet(cmd,
resource_type=CUSTOM_MGMT_FLEET,
operation_group="fleets"
)

managed_service_identity = fleet_managed_service_identity_model(type="None")
if enable_managed_identity:
managed_service_identity.type = "SystemAssigned"
Expand All @@ -104,6 +107,11 @@ def create_fleet(cmd,
elif assign_identity is not None:
raise CLIError("Cannot assign identity without enabling managed identity.")

if enable_vnet_integration:
if not enable_managed_identity and assign_identity is None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. shouldn't this just be if not enable_managed_identity:?
  2. can this test be moved to _validators.py (i.e. add a new validate_enable_vnet_integration function and update _params.py with c.argument('enable_vnet_integration', validator=validate_enable_vnet_integration, ...)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to _validators.py

raise CLIError("When vnet integration is enabled, either system-assigned or "
"user-assigned identity must be provided.")

fleet = fleet_model(
location=location,
tags=tags,
Expand All @@ -112,7 +120,17 @@ def create_fleet(cmd,
)

if enable_private_cluster:
assign_network_contributor_role_to_subnet(cmd, agent_subnet_id)
# provider registration state being is checked to ensure that the Fleet service principal is available
# to create the role assignment on the subnet
if not is_rp_registered(cmd):
raise CLIError("The Microsoft.ContainerService resource provider is not registered."
"Run `az provider register -n Microsoft.ContainerService --wait`.")
assign_network_contributor_role_to_subnet(cmd, FLEET_1P_APP_ID, agent_subnet_id)

if enable_vnet_integration and assign_identity is not None:
object_id = get_msi_object_id(cmd, assign_identity)
assign_network_contributor_role_to_subnet(cmd, object_id, apiserver_subnet_id)
assign_network_contributor_role_to_subnet(cmd, object_id, agent_subnet_id)

return sdk_no_wait(no_wait,
client.begin_create_or_update,
Expand Down
2 changes: 1 addition & 1 deletion src/fleet/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# TODO: Confirm this is the right version number you want and it matches your
# HISTORY.rst entry.
VERSION = '1.6.2'
VERSION = '1.6.5'

# The full list of classifiers is available at
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
Expand Down
Loading