Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
101 changes: 100 additions & 1 deletion src/aks-preview/azext_aks_preview/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
140 changes: 140 additions & 0 deletions src/aks-preview/azext_aks_preview/tests/latest/test_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down