From 7ad8f0d38903a43fb5b32801314316923b365c70 Mon Sep 17 00:00:00 2001 From: FumingZhang <81607949+FumingZhang@users.noreply.github.com> Date: Mon, 18 Oct 2021 17:19:32 +0800 Subject: [PATCH] {AKS} Refactor 2nd part of the create sub-command in aks-preview module (#3964) * refactor http_proxy_config & node_resource_group * fix lint --- .../azext_aks_preview/decorator.py | 101 ++++++++++++- .../tests/latest/test_decorator.py | 140 ++++++++++++++++++ 2 files changed, 240 insertions(+), 1 deletion(-) diff --git a/src/aks-preview/azext_aks_preview/decorator.py b/src/aks-preview/azext_aks_preview/decorator.py index 14408f7b8d7..d23567a38f0 100644 --- a/src/aks-preview/azext_aks_preview/decorator.py +++ b/src/aks-preview/azext_aks_preview/decorator.py @@ -15,7 +15,10 @@ safe_list_get, ) from azure.cli.core import AzCommandsLoader -from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.azclierror import ( + CLIInternalError, + InvalidArgumentValueError, +) from azure.cli.core.commands import AzCliCommand from azure.cli.core.profiles import ResourceType from azure.cli.core.util import get_file_json @@ -31,6 +34,7 @@ ResourceReference = TypeVar("ResourceReference") KubeletConfig = TypeVar("KubeletConfig") LinuxOSConfig = TypeVar("LinuxOSConfig") +ManagedClusterHTTPProxyConfig = TypeVar("ManagedClusterHTTPProxyConfig") # pylint: disable=too-many-instance-attributes,too-few-public-methods @@ -48,6 +52,11 @@ def __init__(self, cmd: AzCommandsLoader, resource_type: ResourceType): resource_type=self.resource_type, operation_group="managed_clusters", ) + self.ManagedClusterHTTPProxyConfig = self.__cmd.get_models( + "ManagedClusterHTTPProxyConfig", + resource_type=self.resource_type, + operation_group="managed_clusters", + ) # pylint: disable=too-many-public-methods @@ -229,6 +238,54 @@ def get_linux_os_config(self) -> Union[dict, LinuxOSConfig, None]: # this parameter does not need validation return linux_os_config + def get_http_proxy_config(self) -> Union[dict, ManagedClusterHTTPProxyConfig, None]: + """Obtain the value of http_proxy_config. + + :return: dict, ManagedClusterHTTPProxyConfig or None + """ + # read the original value passed by the command + http_proxy_config = None + http_proxy_config_file_path = self.raw_param.get("http_proxy_config") + # validate user input + if http_proxy_config_file_path: + if not os.path.isfile(http_proxy_config_file_path): + raise InvalidArgumentValueError( + "{} is not valid file, or not accessable.".format( + http_proxy_config_file_path + ) + ) + http_proxy_config = get_file_json(http_proxy_config_file_path) + if not isinstance(http_proxy_config, dict): + raise InvalidArgumentValueError( + "Error reading Http Proxy Config from {}. " + "Please see https://aka.ms/HttpProxyConfig for correct format.".format( + http_proxy_config_file_path + ) + ) + + # try to read the property value corresponding to the parameter from the `mc` object + if self.mc and self.mc.http_proxy_config is not None: + http_proxy_config = self.mc.http_proxy_config + + # this parameter does not need dynamic completion + # this parameter does not need validation + return http_proxy_config + + def get_node_resource_group(self) -> Union[str, None]: + """Obtain the value of node_resource_group. + + :return: string or None + """ + # read the original value passed by the command + node_resource_group = self.raw_param.get("node_resource_group") + # try to read the property value corresponding to the parameter from the `mc` object + if self.mc and self.mc.node_resource_group is not None: + node_resource_group = self.mc.node_resource_group + + # this parameter does not need dynamic completion + # this parameter does not need validation + return node_resource_group + class AKSPreviewCreateDecorator(AKSCreateDecorator): # pylint: disable=super-init-not-called @@ -279,6 +336,48 @@ def set_up_agent_pool_profiles(self, mc: ManagedCluster) -> ManagedCluster: agent_pool_profile.linux_os_config = self.context.get_linux_os_config() return mc + def set_up_http_proxy_config(self, mc: ManagedCluster) -> ManagedCluster: + """Set up http proxy config for the ManagedCluster object. + + :return: the ManagedCluster object + """ + if not isinstance(mc, self.models.ManagedCluster): + raise CLIInternalError( + "Unexpected mc object with type '{}'.".format(type(mc)) + ) + + mc.http_proxy_config = self.context.get_http_proxy_config() + return mc + + def set_up_node_resource_group(self, mc: ManagedCluster) -> ManagedCluster: + """Set up node resource group for the ManagedCluster object. + + :return: the ManagedCluster object + """ + if not isinstance(mc, self.models.ManagedCluster): + raise CLIInternalError( + "Unexpected mc object with type '{}'.".format(type(mc)) + ) + + mc.node_resource_group = self.context.get_node_resource_group() + return mc + + def construct_preview_mc_profile(self) -> ManagedCluster: + """The overall controller used to construct the preview ManagedCluster profile. + + The completely constructed ManagedCluster object will later be passed as a parameter to the underlying SDK + (mgmt-containerservice) to send the actual request. + + :return: the ManagedCluster object + """ + # construct the default ManagedCluster profile + mc = self.construct_default_mc_profile() + # set up http proxy config + mc = self.set_up_http_proxy_config(mc) + # set up node resource group + mc = self.set_up_node_resource_group(mc) + return mc + class AKSPreviewUpdateDecorator(AKSUpdateDecorator): # pylint: disable=super-init-not-called diff --git a/src/aks-preview/azext_aks_preview/tests/latest/test_decorator.py b/src/aks-preview/azext_aks_preview/tests/latest/test_decorator.py index ed9c9a33e0b..661c1cde97d 100644 --- a/src/aks-preview/azext_aks_preview/tests/latest/test_decorator.py +++ b/src/aks-preview/azext_aks_preview/tests/latest/test_decorator.py @@ -50,6 +50,10 @@ def test_models(self): self.assertEqual(models.KubeletConfig, getattr(module, "KubeletConfig")) self.assertEqual(models.LinuxOSConfig, getattr(module, "LinuxOSConfig")) + self.assertEqual( + models.ManagedClusterHTTPProxyConfig, + getattr(module, "ManagedClusterHTTPProxyConfig"), + ) class AKSPreviewContextTestCase(unittest.TestCase): @@ -227,6 +231,69 @@ def test_get_linux_os_config(self): with self.assertRaises(InvalidArgumentValueError): ctx_3.get_linux_os_config() + def test_get_http_proxy_config(self): + # default + ctx_1 = AKSPreviewContext( + self.cmd, + {"http_proxy_config": None}, + self.models, + decorator_mode=DecoratorMode.CREATE, + ) + self.assertEqual(ctx_1.get_http_proxy_config(), None) + mc = self.models.ManagedCluster( + location="test_location", + http_proxy_config=self.models.ManagedClusterHTTPProxyConfig( + http_proxy="test_http_proxy" + ), + ) + ctx_1.attach_mc(mc) + self.assertEqual( + ctx_1.get_http_proxy_config(), + self.models.ManagedClusterHTTPProxyConfig( + http_proxy="test_http_proxy" + ), + ) + + # custom value + ctx_2 = AKSPreviewContext( + self.cmd, + {"http_proxy_config": "fake-path"}, + self.models, + decorator_mode=DecoratorMode.CREATE, + ) + # fail on invalid file path + with self.assertRaises(InvalidArgumentValueError): + ctx_2.get_http_proxy_config() + + # custom value + ctx_3 = AKSPreviewContext( + self.cmd, + {"http_proxy_config": _get_test_data_file("invalidconfig.json")}, + self.models, + decorator_mode=DecoratorMode.CREATE, + ) + # fail on invalid file path + with self.assertRaises(InvalidArgumentValueError): + ctx_3.get_http_proxy_config() + + def test_get_node_resource_group(self): + # default + ctx_1 = AKSPreviewContext( + self.cmd, + {"node_resource_group": None}, + self.models, + decorator_mode=DecoratorMode.CREATE, + ) + self.assertEqual(ctx_1.get_node_resource_group(), None) + mc = self.models.ManagedCluster( + location="test_location", + node_resource_group="test_node_resource_group", + ) + ctx_1.attach_mc(mc) + self.assertEqual( + ctx_1.get_node_resource_group(), "test_node_resource_group" + ) + class AKSPreviewCreateDecoratorTestCase(unittest.TestCase): def setUp(self): @@ -400,6 +467,79 @@ def test_set_up_agent_pool_profiles(self): ground_truth_mc_2.agent_pool_profiles = [agent_pool_profile_2] self.assertEqual(dec_mc_2, ground_truth_mc_2) + def test_set_up_http_proxy_config(self): + # default value in `aks_create` + dec_1 = AKSPreviewCreateDecorator( + self.cmd, + self.client, + { + "http_proxy_config": None, + }, + CUSTOM_MGMT_AKS_PREVIEW, + ) + mc_1 = self.models.ManagedCluster(location="test_location") + # fail on passing the wrong mc object + with self.assertRaises(CLIInternalError): + dec_1.set_up_http_proxy_config(None) + dec_mc_1 = dec_1.set_up_http_proxy_config(mc_1) + ground_truth_mc_1 = self.models.ManagedCluster(location="test_location") + self.assertEqual(dec_mc_1, ground_truth_mc_1) + + # custom value + dec_2 = AKSPreviewCreateDecorator( + self.cmd, + self.client, + {"http_proxy_config": _get_test_data_file("httpproxyconfig.json")}, + CUSTOM_MGMT_AKS_PREVIEW, + ) + mc_2 = self.models.ManagedCluster(location="test_location") + dec_mc_2 = dec_2.set_up_http_proxy_config(mc_2) + ground_truth_mc_2 = self.models.ManagedCluster( + location="test_location", + http_proxy_config={ + "httpProxy": "http://myproxy.server.com:8080/", + "httpsProxy": "https://myproxy.server.com:8080/", + "noProxy": ["localhost", "127.0.0.1"], + }, + ) + self.assertEqual(dec_mc_2, ground_truth_mc_2) + + def test_set_up_node_resource_group(self): + # default value in `aks_create` + dec_1 = AKSPreviewCreateDecorator( + self.cmd, + self.client, + { + "node_resource_group": None, + }, + CUSTOM_MGMT_AKS_PREVIEW, + ) + mc_1 = self.models.ManagedCluster(location="test_location") + # fail on passing the wrong mc object + with self.assertRaises(CLIInternalError): + dec_1.set_up_node_resource_group(None) + dec_mc_1 = dec_1.set_up_node_resource_group(mc_1) + ground_truth_mc_1 = self.models.ManagedCluster(location="test_location") + self.assertEqual(dec_mc_1, ground_truth_mc_1) + + # custom value + dec_2 = AKSPreviewCreateDecorator( + self.cmd, + self.client, + {"node_resource_group": "test_node_resource_group"}, + CUSTOM_MGMT_AKS_PREVIEW, + ) + mc_2 = self.models.ManagedCluster(location="test_location") + dec_mc_2 = dec_2.set_up_node_resource_group(mc_2) + ground_truth_mc_2 = self.models.ManagedCluster( + location="test_location", + node_resource_group="test_node_resource_group", + ) + self.assertEqual(dec_mc_2, ground_truth_mc_2) + + def test_construct_preview_mc_profile(self): + pass + class AKSPreviewUpdateDecoratorTestCase(unittest.TestCase): def setUp(self):