Skip to content
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

{AKS-preview} Get aks monitoring MSI auth onboarding changes in-sync with azure cli #5065

Merged
merged 7 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 8 additions & 212 deletions src/aks-preview/azext_aks_preview/addonconfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@
import json
from knack.log import get_logger
from knack.util import CLIError
from azure.cli.core.azclierror import ArgumentUsageError, ClientRequestError
from azure.cli.core.azclierror import AzCLIError, ArgumentUsageError, ClientRequestError
ganga1980 marked this conversation as resolved.
Show resolved Hide resolved
from azure.cli.core.commands import LongRunningOperation
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.util import sdk_no_wait
from azure.cli.core.util import sdk_no_wait, send_raw_request
from azure.core.exceptions import HttpResponseError
from azure.cli.command_modules.acs.addonconfiguration import (
ensure_container_insights_for_monitoring,
sanitize_loganalytics_ws_resource_id,
ensure_default_log_analytics_workspace_for_monitoring
ganga1980 marked this conversation as resolved.
Show resolved Hide resolved
)
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW
from azext_aks_preview._client_factory import get_resources_client, get_resource_groups_client
from azext_aks_preview._resourcegroup import get_rg_location
Expand Down Expand Up @@ -494,216 +500,6 @@ def ensure_default_log_analytics_workspace_for_monitoring(cmd, subscription_id,
return ws_resource_id


def sanitize_loganalytics_ws_resource_id(workspace_resource_id):
workspace_resource_id = workspace_resource_id.strip()
if not workspace_resource_id.startswith('/'):
workspace_resource_id = '/' + workspace_resource_id
if workspace_resource_id.endswith('/'):
workspace_resource_id = workspace_resource_id.rstrip('/')
return workspace_resource_id


def ensure_container_insights_for_monitoring(cmd,
addon,
cluster_subscription,
cluster_resource_group_name,
cluster_name,
cluster_region,
remove_monitoring=False,
aad_route=False,
create_dcr=False,
create_dcra=False):
"""
Either adds the ContainerInsights solution to a LA Workspace OR sets up a DCR (Data Collection Rule) and DCRA
(Data Collection Rule Association). Both let the monitoring addon send data to a Log Analytics Workspace.

Set aad_route == True to set up the DCR data route. Otherwise the solution route will be used. Create_dcr and
create_dcra have no effect if aad_route == False.

Set remove_monitoring to True and create_dcra to True to remove the DCRA from a cluster. The association makes
it very hard to delete either the DCR or cluster. (It is not obvious how to even navigate to the association from
the portal, and it prevents the cluster and DCR from being deleted individually).
"""
if not addon.enabled:
return None

# workaround for this addon key which has been seen lowercased in the wild
for key in list(addon.config):
if key.lower() == CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID.lower() and key != CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID:
addon.config[CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID] = addon.config.pop(
key)

workspace_resource_id = addon.config[CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID].strip(
)
if not workspace_resource_id.startswith('/'):
workspace_resource_id = '/' + workspace_resource_id

if workspace_resource_id.endswith('/'):
workspace_resource_id = workspace_resource_id.rstrip('/')

# extract subscription ID and resource group from workspace_resource_id URL
try:
subscription_id = workspace_resource_id.split('/')[2]
resource_group = workspace_resource_id.split('/')[4]
workspace_name = workspace_resource_id.split('/')[8]
except IndexError:
raise CLIError(
'Could not locate resource group in workspace-resource-id URL.')

# region of workspace can be different from region of RG so find the location of the workspace_resource_id
if not remove_monitoring:
resources = get_resources_client(cmd.cli_ctx, subscription_id)
from azure.core.exceptions import HttpResponseError
try:
resource = resources.get_by_id(
workspace_resource_id, '2015-11-01-preview')
location = resource.location
except HttpResponseError as ex:
raise ex

if aad_route:
cluster_resource_id = f"/subscriptions/{cluster_subscription}/resourceGroups/{cluster_resource_group_name}/providers/Microsoft.ContainerService/managedClusters/{cluster_name}"
dataCollectionRuleName = f"MSCI-{workspace_name}"
dcr_resource_id = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Insights/dataCollectionRules/{dataCollectionRuleName}"
from azure.cli.core.util import send_raw_request
from azure.cli.core.profiles import ResourceType

if create_dcr:
# first get the association between region display names and region IDs (because for some reason
# the "which RPs are available in which regions" check returns region display names)
region_names_to_id = {}
# retry the request up to two times
for _ in range(3):
try:
location_list_url = f"https://management.azure.com/subscriptions/{subscription_id}/locations?api-version=2019-11-01"
r = send_raw_request(cmd.cli_ctx, "GET", location_list_url)

# this is required to fool the static analyzer. The else statement will only run if an exception
# is thrown, but flake8 will complain that e is undefined if we don't also define it here.
error = None
break
except CLIError as e:
error = e
else:
# This will run if the above for loop was not broken out of. This means all three requests failed
raise error
json_response = json.loads(r.text)
for region_data in json_response["value"]:
region_names_to_id[region_data["displayName"]
] = region_data["name"]

# check if region supports DCRs and DCR-A
for _ in range(3):
try:
feature_check_url = f"https://management.azure.com/subscriptions/{subscription_id}/providers/Microsoft.Insights?api-version=2020-10-01"
r = send_raw_request(cmd.cli_ctx, "GET", feature_check_url)
error = None
break
except CLIError as e:
error = e
else:
raise error
json_response = json.loads(r.text)
for resource in json_response["resourceTypes"]:
region_ids = map(lambda x: region_names_to_id[x],
resource["locations"]) # map is lazy, so doing this for every region isn't slow
if resource["resourceType"].lower() == "datacollectionrules" and location not in region_ids:
raise ClientRequestError(
f'Data Collection Rules are not supported for LA workspace region {location}')
elif resource[
"resourceType"].lower() == "datacollectionruleassociations" and cluster_region not in region_ids:
raise ClientRequestError(
f'Data Collection Rule Associations are not supported for cluster region {location}')

# create the DCR
dcr_creation_body = json.dumps({"location": location,
"properties": {
"dataSources": {
"extensions": [
{
"name": "ContainerInsightsExtension",
"streams": [
"Microsoft-Perf",
"Microsoft-ContainerInventory",
"Microsoft-ContainerLog",
"Microsoft-ContainerLogV2",
"Microsoft-ContainerNodeInventory",
"Microsoft-KubeEvents",
"Microsoft-KubeHealth",
"Microsoft-KubeMonAgentEvents",
"Microsoft-KubeNodeInventory",
"Microsoft-KubePodInventory",
"Microsoft-KubePVInventory",
"Microsoft-KubeServices",
"Microsoft-InsightsMetrics"
],
"extensionName": "ContainerInsights"
}
]
},
"dataFlows": [
{
"streams": [
"Microsoft-Perf",
"Microsoft-ContainerInventory",
"Microsoft-ContainerLog",
"Microsoft-ContainerLogV2",
"Microsoft-ContainerNodeInventory",
"Microsoft-KubeEvents",
"Microsoft-KubeHealth",
"Microsoft-KubeMonAgentEvents",
"Microsoft-KubeNodeInventory",
"Microsoft-KubePodInventory",
"Microsoft-KubePVInventory",
"Microsoft-KubeServices",
"Microsoft-InsightsMetrics"
],
"destinations": [
"la-workspace"
]
}
],
"destinations": {
"logAnalytics": [
{
"workspaceResourceId": workspace_resource_id,
"name": "la-workspace"
}
]
}
}})
dcr_url = f"https://management.azure.com/{dcr_resource_id}?api-version=2019-11-01-preview"
for _ in range(3):
try:
send_raw_request(cmd.cli_ctx, "PUT",
dcr_url, body=dcr_creation_body)
error = None
break
except CLIError as e:
error = e
else:
raise error

if create_dcra:
# only create or delete the association between the DCR and cluster
association_body = json.dumps({"location": cluster_region,
"properties": {
"dataCollectionRuleId": dcr_resource_id,
"description": "routes monitoring data to a Log Analytics workspace"
}})
association_url = f"https://management.azure.com/{cluster_resource_id}/providers/Microsoft.Insights/dataCollectionRuleAssociations/send-to-{workspace_name}?api-version=2019-11-01-preview"
for _ in range(3):
try:
send_raw_request(cmd.cli_ctx, "PUT" if not remove_monitoring else "DELETE", association_url,
body=association_body)
error = None
break
except CLIError as e:
error = e
else:
raise error


def add_monitoring_role_assignment(result, cluster_resource_id, cmd):
service_principal_msi_id = None
# Check if service principal exists, if it does, assign permissions to service principal
Expand Down
11 changes: 7 additions & 4 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
from six.moves.urllib.error import URLError
from six.moves.urllib.request import urlopen

from azure.cli.command_modules.acs.addonconfiguration import (
ensure_container_insights_for_monitoring,
sanitize_loganalytics_ws_resource_id,
ensure_default_log_analytics_workspace_for_monitoring
)

from azext_aks_preview._client_factory import (
CUSTOM_MGMT_AKS_PREVIEW,
cf_agent_pools,
Expand Down Expand Up @@ -97,10 +103,7 @@
add_ingress_appgw_addon_role_assignment,
add_monitoring_role_assignment,
add_virtual_node_role_assignment,
enable_addons,
ensure_container_insights_for_monitoring,
ensure_default_log_analytics_workspace_for_monitoring,
sanitize_loganalytics_ws_resource_id,
enable_addons
)
from azext_aks_preview.aks_draft.commands import (
aks_draft_cmd_create,
Expand Down
Loading