Skip to content

Commit 1698603

Browse files
authored
[Connectedk8s] Non-existing namespace deploy check + Error experience Improvement (Azure#3736)
* Added error fix * Fix * big bang * lint fix * Fixe * Nit * Up * Fix
1 parent 927c622 commit 1698603

File tree

5 files changed

+92
-4
lines changed

5 files changed

+92
-4
lines changed

src/connectedk8s/HISTORY.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
Release History
44
===============
55

6+
7+
1.1.7
8+
++++++
9+
* Add non-existing namespace deploy check
10+
* Improve some error and warning experiences
11+
12+
613
1.1.6
714
++++++
815
* Moved to track2 SDK

src/connectedk8s/azext_connectedk8s/_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
Infrastructure_Enum_Values = ["auto", "generic", "azure", "aws", "gcp", "azure_stack_hci", "azure_stack_hub", "azure_stack_edge", "vsphere", "windows_server"]
1111
Feature_Values = ["cluster-connect", "azure-rbac", "custom-locations"]
1212
Custom_Locations_Provider_Namespace = 'Microsoft.ExtendedLocation'
13+
Connected_Cluster_Provider_Namespace = 'Microsoft.Kubernetes'
14+
Kubernetes_Configuration_Provider_Namespace = 'Microsoft.KubernetesConfiguration'
15+
Arc_Namespace = 'azure-arc'
1316

1417
Azure_PublicCloudName = 'AZUREPUBLICCLOUD'
1518
Azure_USGovCloudName = 'AZUREUSGOVERNMENTCLOUD'
@@ -101,6 +104,9 @@
101104
Error_enabling_Features = 'Error while updating agents for enabling features. Please run \"kubectl get pods -n azure-arc\" to check the pods in case of timeout error. Error: {}'
102105
Error_disabling_Features = 'Error while updating agents for disabling features. Please run \"kubectl get pods -n azure-arc\" to check the pods in case of timeout error. Error: {}'
103106
Proxy_Kubeconfig_During_Deletion_Fault_Type = 'Encountered proxy kubeconfig during deletion.'
107+
Cannot_Create_ClusterRoleBindings_Fault_Type = 'Cannot create cluster role bindings on this Kubernets cluster'
108+
CC_Provider_Namespace_Not_Registered_Fault_Type = "Connected Cluster Provider MS.K8 namespace not registered"
109+
Default_Namespace_Does_Not_Exist_Fault_Type = "The default namespace defined in the kubeconfig doesn't exist on the kubernetes cluster."
104110
CLIENT_PROXY_VERSION = '1.1.0'
105111
API_SERVER_PORT = 47011
106112
CLIENT_PROXY_PORT = 47010

src/connectedk8s/azext_connectedk8s/_utils.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
from azure.cli.core.util import send_raw_request
2121
from azure.cli.core import telemetry
2222
from azure.core.exceptions import ResourceNotFoundError
23-
from msrest.exceptions import AuthenticationError, HttpOperationError, TokenExpiredError, ValidationError
23+
from msrest.exceptions import AuthenticationError, HttpOperationError, TokenExpiredError
24+
from msrest.exceptions import ValidationError as MSRestValidationError
2425
from msrestazure.azure_exceptions import CloudError
2526
from kubernetes.client.rest import ApiException
26-
from azext_connectedk8s._client_factory import _resource_client_factory
27+
from azext_connectedk8s._client_factory import _resource_client_factory, _resource_providers_client
2728
import azext_connectedk8s._constants as consts
2829
from kubernetes import client as kube_client
2930
from azure.cli.core.azclierror import CLIInternalError, ClientRequestError, ArgumentUsageError, ManualInterrupt, AzureResponseError, AzureInternalError, ValidationError
@@ -183,7 +184,7 @@ def arm_exception_handler(ex, fault_type, summary, return_if_not_found=False):
183184
raise AzureInternalError("Http operation error occured while making ARM request: " + str(ex) + "\nSummary: {}".format(summary))
184185
raise AzureResponseError("Http operation error occured while making ARM request: " + str(ex) + "\nSummary: {}".format(summary))
185186

186-
if isinstance(ex, ValidationError):
187+
if isinstance(ex, MSRestValidationError):
187188
telemetry.set_exception(exception=ex, fault_type=fault_type, summary=summary)
188189
raise AzureResponseError("Validation error occured while making ARM request: " + str(ex) + "\nSummary: {}".format(summary))
189190

@@ -395,3 +396,38 @@ def names(self, names):
395396
V1ContainerImage.names = V1ContainerImage.names.setter(names)
396397
except Exception as ex:
397398
logger.debug("Error while trying to monkey patch the fix for list_node(): {}".format(str(ex)))
399+
400+
401+
def check_provider_registrations(cli_ctx):
402+
try:
403+
rp_client = _resource_providers_client(cli_ctx)
404+
cc_registration_state = rp_client.get(consts.Connected_Cluster_Provider_Namespace).registration_state
405+
if cc_registration_state != "Registered":
406+
telemetry.set_exception(exception="{} provider is not registered".format(consts.Connected_Cluster_Provider_Namespace), fault_type=consts.CC_Provider_Namespace_Not_Registered_Fault_Type,
407+
summary="{} provider is not registered".format(consts.Connected_Cluster_Provider_Namespace))
408+
raise ValidationError("{} provider is not registered. Please register it using 'az provider register -n 'Microsoft.Kubernetes' before running the connect command.".format(consts.Connected_Cluster_Provider_Namespace))
409+
kc_registration_state = rp_client.get(consts.Kubernetes_Configuration_Provider_Namespace).registration_state
410+
if kc_registration_state != "Registered":
411+
telemetry.set_user_fault()
412+
logger.warning("{} provider is not registered".format(consts.Kubernetes_Configuration_Provider_Namespace))
413+
except ValidationError as e:
414+
raise e
415+
except Exception as ex:
416+
logger.warning("Couldn't check the required provider's registration status. Error: {}".format(str(ex)))
417+
418+
419+
def can_create_clusterrolebindings(configuration):
420+
try:
421+
api_instance = kube_client.AuthorizationV1Api(kube_client.ApiClient(configuration))
422+
access_review = kube_client.V1SelfSubjectAccessReview(spec={
423+
"resourceAttributes": {
424+
"verb": "create",
425+
"resource": "clusterrolebindings",
426+
"group": "rbac.authorization.k8s.io"
427+
}
428+
})
429+
response = api_instance.create_self_subject_access_review(access_review)
430+
return response.status.allowed
431+
except Exception as ex:
432+
logger.warning("Couldn't check for the permission to create clusterrolebindings on this k8s cluster. Error: {}".format(str(ex)))
433+
return "Unknown"

src/connectedk8s/azext_connectedk8s/custom.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
7272
graph_client = _graph_client_factory(cmd.cli_ctx)
7373
onboarding_tenant_id = graph_client.config.tenant_id
7474

75+
# Checking provider registration status
76+
utils.check_provider_registrations(cmd.cli_ctx)
77+
7578
# Setting kubeconfig
7679
kube_config = set_kube_config(kube_config)
7780

@@ -119,6 +122,12 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
119122
summary="Couldn't find any node on the kubernetes cluster with the architecture type 'amd64' and OS 'linux'")
120123
logger.warning("Please ensure that this Kubernetes cluster have any nodes with OS 'linux' and architecture 'amd64', for scheduling the Arc-Agents onto and connecting to Azure. Learn more at {}".format("https://aka.ms/ArcK8sSupportedOSArchitecture"))
121124

125+
crb_permission = utils.can_create_clusterrolebindings(configuration)
126+
if not crb_permission:
127+
telemetry.set_exception(exception="Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster.", fault_type=consts.Cannot_Create_ClusterRoleBindings_Fault_Type,
128+
summary="Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster.")
129+
raise ValidationError("Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster. Please check your permissions.")
130+
122131
# Get kubernetes cluster info
123132
kubernetes_version = get_server_version(configuration)
124133

@@ -200,6 +209,36 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
200209
"and corresponds to a different Kubernetes cluster.", recommendation="To onboard this Kubernetes cluster " +
201210
"to Azure, specify different resource name or resource group name.")
202211

212+
try:
213+
k8s_contexts = config.list_kube_config_contexts() # returns tuple of (all_contexts, current_context)
214+
if kube_context: # if custom kube-context is specified
215+
if k8s_contexts[1].get('name') == kube_context:
216+
current_k8s_context = k8s_contexts[1]
217+
else:
218+
for context in k8s_contexts[0]:
219+
if context.get('name') == kube_context:
220+
current_k8s_context = context
221+
break
222+
else:
223+
current_k8s_context = k8s_contexts[1]
224+
225+
current_k8s_namespace = current_k8s_context.get('context').get('namespace', "default") # Take "default" namespace, if not specified in the kube-config
226+
namespace_exists = False
227+
k8s_v1 = kube_client.CoreV1Api()
228+
k8s_ns = k8s_v1.list_namespace()
229+
for ns in k8s_ns.items:
230+
if ns.metadata.name == current_k8s_namespace:
231+
namespace_exists = True
232+
break
233+
if namespace_exists is False:
234+
telemetry.set_exception(exception="Namespace doesn't exist", fault_type=consts.Default_Namespace_Does_Not_Exist_Fault_Type,
235+
summary="The default namespace defined in the kubeconfig doesn't exist on the kubernetes cluster.")
236+
raise ValidationError("The default namespace '{}' defined in the kubeconfig doesn't exist on the kubernetes cluster.".format(current_k8s_namespace))
237+
except ValidationError as e:
238+
raise e
239+
except Exception as e:
240+
logger.warning("Failed to validate if the active namespace exists on the kubernetes cluster. Exception: {}".format(str(e)))
241+
203242
# Resource group Creation
204243
if resource_group_exists(cmd.cli_ctx, resource_group_name, subscription_id) is False:
205244
from azure.cli.core.profiles import ResourceType

src/connectedk8s/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# TODO: Confirm this is the right version number you want and it matches your
1818
# HISTORY.rst entry.
1919

20-
VERSION = '1.1.6'
20+
VERSION = '1.1.7'
2121

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

0 commit comments

Comments
 (0)