Skip to content
Merged
6 changes: 6 additions & 0 deletions src/connectedk8s/azext_connectedk8s/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
Infrastructure_Enum_Values = ["auto", "generic", "azure", "aws", "gcp", "azure_stack_hci", "azure_stack_hub", "azure_stack_edge", "vsphere", "windows_server"]
Feature_Values = ["cluster-connect", "azure-rbac", "custom-locations"]
Custom_Locations_Provider_Namespace = 'Microsoft.ExtendedLocation'
Connected_Cluster_Provider_Namespace = 'Microsoft.Kubernetes'
Kubernetes_Configuration_Provider_Namespace = 'Microsoft.KubernetesConfiguration'
Arc_Namespace = 'azure-arc'

Azure_PublicCloudName = 'AZUREPUBLICCLOUD'
Azure_USGovCloudName = 'AZUREUSGOVERNMENTCLOUD'
Expand Down Expand Up @@ -101,6 +104,9 @@
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: {}'
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: {}'
Proxy_Kubeconfig_During_Deletion_Fault_Type = 'Encountered proxy kubeconfig during deletion.'
Cant_Create_ClusterRoleBindings_Fault_Type = 'Cannot create cluster role bindings on this Kubernets cluster'
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
CC_Provider_Namespace_Not_Registered_Fault_Type = "Connected Cluster Provider MS.K8 namespace not registered"
Namespace_Does_Not_Exist_Fault_Type = "The default namespace defined in the kubeconfig doesn't exist on the kubernetes cluster."
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
CLIENT_PROXY_VERSION = '1.1.0'
API_SERVER_PORT = 47011
CLIENT_PROXY_PORT = 47010
Expand Down
39 changes: 36 additions & 3 deletions src/connectedk8s/azext_connectedk8s/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
from azure.cli.core.util import send_raw_request
from azure.cli.core import telemetry
from azure.core.exceptions import ResourceNotFoundError
from msrest.exceptions import AuthenticationError, HttpOperationError, TokenExpiredError, ValidationError
from msrest.exceptions import AuthenticationError, HttpOperationError, TokenExpiredError
from msrest.exceptions import ValidationError as MSRestValidationError
from msrestazure.azure_exceptions import CloudError
from kubernetes.client.rest import ApiException
from azext_connectedk8s._client_factory import _resource_client_factory
from azext_connectedk8s._client_factory import _resource_client_factory, _resource_providers_client
import azext_connectedk8s._constants as consts
from kubernetes import client as kube_client
from azure.cli.core.azclierror import CLIInternalError, ClientRequestError, ArgumentUsageError, ManualInterrupt, AzureResponseError, AzureInternalError, ValidationError
Expand Down Expand Up @@ -183,7 +184,7 @@ def arm_exception_handler(ex, fault_type, summary, return_if_not_found=False):
raise AzureInternalError("Http operation error occured while making ARM request: " + str(ex) + "\nSummary: {}".format(summary))
raise AzureResponseError("Http operation error occured while making ARM request: " + str(ex) + "\nSummary: {}".format(summary))

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

Expand Down Expand Up @@ -395,3 +396,35 @@ def names(self, names):
V1ContainerImage.names = V1ContainerImage.names.setter(names)
except Exception as ex:
logger.debug("Error while trying to monkey patch the fix for list_node(): {}".format(str(ex)))


def check_provider_registrations(cli_ctx):
try:
rp_client = _resource_providers_client(cli_ctx)
cc_registration_state = rp_client.get(consts.Connected_Cluster_Provider_Namespace).registration_state
if cc_registration_state != "Registered":
telemetry.set_exception(exception="{} provider is not registered".format(consts.Connected_Cluster_Provider_Namespace), fault_type=consts.CC_Provider_Namespace_Not_Registered_Fault_Type,
Comment thread
alphaWizard marked this conversation as resolved.
summary="{} provider is not registered".format(consts.Connected_Cluster_Provider_Namespace))
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))
kc_registration_state = rp_client.get(consts.Kubernetes_Configuration_Provider_Namespace).registration_state
if kc_registration_state != "Registered":
logger.warning("{} provider is not registered".format(consts.Kubernetes_Configuration_Provider_Namespace))
except Exception as ex:
logger.warning("Couldn't check the required provider's registration status. Error: {}".format(str(ex)))


def can_create_clusterrolebindings(configuration):
try:
api_instance = kube_client.AuthorizationV1Api(kube_client.ApiClient(configuration))
access_review = kube_client.V1SelfSubjectAccessReview(spec={
"resourceAttributes": {
"verb": "create",
"resource": "clusterrolebindings",
"group": "rbac.authorization.k8s.io"
}
})
response = api_instance.create_self_subject_access_review(access_review)
return response.status.allowed
except Exception as ex:
logger.warning("Couldn't check for the permission to create clusterrolebindings on this k8s cluster. Error: {}".format(str(ex)))
return "Unknown"
Comment thread
alphaWizard marked this conversation as resolved.
26 changes: 26 additions & 0 deletions src/connectedk8s/azext_connectedk8s/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
graph_client = _graph_client_factory(cmd.cli_ctx)
onboarding_tenant_id = graph_client.config.tenant_id

# Checking provider registration status
utils.check_provider_registrations(cmd.cli_ctx)

# Setting kubeconfig
kube_config = set_kube_config(kube_config)

Expand Down Expand Up @@ -119,6 +122,12 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
summary="Couldn't find any node on the kubernetes cluster with the architecture type 'amd64' and OS 'linux'")
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"))

crb_permission = utils.can_create_clusterrolebindings(configuration)
if not crb_permission:
telemetry.set_exception(exception="Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster.", fault_type=consts.Cant_Create_ClusterRoleBindings_Fault_Type,
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
summary="Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster.")
raise ValidationError("Your credentials doesn't have permission to create clusterrolebindings on this kubernetes cluster. Please check your permissions.")

# Get kubernetes cluster info
kubernetes_version = get_server_version(configuration)

Expand Down Expand Up @@ -256,6 +265,23 @@ def create_connectedk8s(cmd, client, resource_group_name, cluster_name, https_pr
# Checking if custom locations rp is registered and fetching oid if it is registered
enable_custom_locations, custom_locations_oid = check_cl_registration_and_get_oid(cmd, cl_oid)

try:
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
current_k8s_context = config.list_kube_config_contexts()[1]['context']
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
current_k8s_namespace = current_k8s_context['namespace']
namespace_exists = False
k8s_v1 = kube_client.CoreV1Api()
k8s_ns = k8s_v1.list_namespace()
for ns in k8s_ns.items:
if ns.metadata.name == current_k8s_namespace:
namespace_exists = True
break
if namespace_exists is False:
telemetry.set_exception(exception="Namespace doesn't exist", fault_type=consts.Namespace_Does_Not_Exist_Fault_Type,
Comment thread
alphaWizard marked this conversation as resolved.
Outdated
summary="The default namespace defined in the kubeconfig doesn't exist on the kubernetes cluster.")
raise ValidationError("The default namespace defined in the kubeconfig doesn't exist on the kubernetes cluster.")
except Exception as e:
logger.warning("Failed to validate if the active namespace exists on the kubernetes cluster. Exception: {}".format(str(e)))

# Install azure-arc agents
utils.helm_install_release(chart_path, subscription_id, kubernetes_distro, kubernetes_infra, resource_group_name, cluster_name,
location, onboarding_tenant_id, http_proxy, https_proxy, no_proxy, proxy_cert, private_key_pem, kube_config,
Expand Down