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] Add mutable fips cli flags (enable/disable on nodepool update) #7752

Merged
merged 6 commits into from
Jun 28, 2024
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
4 changes: 4 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++

5.0.0b3
++++++++
* Add support for mutable fips in agentpool update. (enable/disable flags)

5.0.0b2
++++++++
* Add option `--ephemeral-disk-volume-type` to `az aks create` and `az aks update` for Azure Container Storage operations.
Expand Down
6 changes: 6 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,12 @@
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new node pool to be created, but to prevent updating an existing node pool. Other values will be ignored.
- name: --enable-fips-image
type: bool
short-summary: Switch to use FIPS-enabled OS on agent nodes.
- name: --disable-fips-image
type: bool
short-summary: Switch to use non-FIPS-enabled OS on agent nodes.
examples:
- name: Reconcile the nodepool back to its current state.
text: az aks nodepool update -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster
Expand Down
10 changes: 10 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,16 @@ def load_arguments(self, _):
)
c.argument("if_match")
c.argument("if_none_match")
c.argument(
"enable_fips_image",
is_preview=True,
action="store_true"
)
c.argument(
"disable_fips_image",
is_preview=True,
action="store_true"
)

with self.argument_context("aks nodepool upgrade") as c:
c.argument("max_surge", validator=validate_max_surge)
Expand Down
51 changes: 51 additions & 0 deletions src/aks-preview/azext_aks_preview/agentpool_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,39 @@ def get_vm_sizes(self) -> List[str]:
vm_sizes = [self.get_node_vm_size()]
return vm_sizes

# Overrides azure-cli command to allow changes after create
def get_enable_fips_image(self) -> bool:
"""Obtain the value of enable_fips_image, default value is False.

:return: bool
"""

# read the original value passed by the command
enable_fips_image = self.raw_param.get("enable_fips_image", False)
# In create mode, try and read the property value corresponding to the parameter from the `agentpool` object
if self.decorator_mode == DecoratorMode.CREATE:
if (
self.agentpool and
hasattr(self.agentpool, "enable_fips") and # backward compatibility
self.agentpool.enable_fips is not None
):
enable_fips_image = self.agentpool.enable_fips

# Verify both flags have not been set
if enable_fips_image and self.get_disable_fips_image():
raise MutuallyExclusiveArgumentError(
'Cannot specify "--enable-fips-image" and "--disable-fips-image" at the same time'
)

return enable_fips_image

def get_disable_fips_image(self) -> bool:
"""Obtain the value of disable_fips_image.
:return: bool
"""
# read the original value passed by the command
return self.raw_param.get("disable_fips_image")


class AKSPreviewAgentPoolAddDecorator(AKSAgentPoolAddDecorator):
def __init__(
Expand Down Expand Up @@ -1092,6 +1125,21 @@ def update_vtpm(self, agentpool: AgentPool) -> AgentPool:

return agentpool

def update_fips_image(self, agentpool: AgentPool) -> AgentPool:
"""Update fips image property for the AgentPool object.
:return: the AgentPool object
"""
self._ensure_agentpool(agentpool)

# Updates enable_fips property allowing switching of fips mode
if self.context.get_enable_fips_image():
agentpool.enable_fips = True

if self.context.get_disable_fips_image():
agentpool.enable_fips = False

return agentpool

def update_agentpool_profile_preview(self, agentpools: List[AgentPool] = None) -> AgentPool:
"""The overall controller used to update the preview AgentPool profile.

Expand Down Expand Up @@ -1121,6 +1169,9 @@ def update_agentpool_profile_preview(self, agentpools: List[AgentPool] = None) -
# update os sku
agentpool = self.update_os_sku(agentpool)

# update fips image
agentpool = self.update_fips_image(agentpool)

# update ssh access
agentpool = self.update_ssh_access(agentpool)

Expand Down
2 changes: 2 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,8 @@ def aks_agentpool_update(
disable_vtpm=False,
if_match=None,
if_none_match=None,
enable_fips_image=False,
disable_fips_image=False,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,48 @@ def common_get_disable_vtpm(self):
)
ctx_1.attach_agentpool(agentpool_1)
self.assertEqual(ctx_1.get_disable_vtpm(), True)

def common_get_enable_fips_image(self):
# default
ctx_1 = AKSPreviewAgentPoolContext(
self.cmd,
AKSAgentPoolParamDict({"enable_fips_image": False}),
self.models,
DecoratorMode.CREATE,
self.agentpool_decorator_mode,
)
self.assertEqual(ctx_1.get_enable_fips_image(), False)
agentpool = self.create_initialized_agentpool_instance(enable_fips=True)
ctx_1.attach_agentpool(agentpool)
self.assertEqual(ctx_1.get_enable_fips_image(), True)

# default
ctx_2 = AKSPreviewAgentPoolContext(
self.cmd,
AKSAgentPoolParamDict({"enable_fips_image": False}),
self.models,
DecoratorMode.UPDATE,
self.agentpool_decorator_mode,
)
self.assertEqual(ctx_2.get_enable_fips_image(), False)
agentpool_2 = self.create_initialized_agentpool_instance(enable_fips=True)
ctx_2.attach_agentpool(agentpool_2)
# Update takes directly from flag value not from agentpool property
self.assertEqual(ctx_2.get_enable_fips_image(), False)

def common_get_disable_fips_image(self):
# default
ctx_1 = AKSPreviewAgentPoolContext(
self.cmd,
AKSAgentPoolParamDict({"disable_fips_image": True}),
self.models,
DecoratorMode.UPDATE,
self.agentpool_decorator_mode,
)
self.assertEqual(ctx_1.get_disable_fips_image(), True)
agentpool_1 = self.create_initialized_agentpool_instance(enable_fips=True)
ctx_1.attach_agentpool(agentpool_1)
self.assertEqual(ctx_1.get_disable_fips_image(), True)

def common_get_agentpool_windows_profile(self):
ctx_1 = AKSPreviewAgentPoolContext(
Expand Down Expand Up @@ -805,6 +847,12 @@ def test_get_enable_vtpm(self):

def test_get_disable_vtpm(self):
self.common_get_disable_vtpm()

def common_get_enable_fips_image(self):
self.common_get_enable_fips_image()

def common_get_disable_fips_image(self):
self.common_get_disable_fips_image()

def test_get_agentpool_windows_profile(self):
self.common_get_agentpool_windows_profile()
Expand Down Expand Up @@ -871,6 +919,9 @@ def test_get_disable_secure_boot(self):

def test_get_enable_vtpm(self):
self.common_get_enable_vtpm()

def common_get_enable_fips_image(self):
self.common_get_enable_fips_image()

def test_get_agentpool_windows_profile(self):
self.common_get_agentpool_windows_profile()
Expand Down Expand Up @@ -1681,6 +1732,53 @@ def common_update_vtpm(self):
with self.assertRaises(MutuallyExclusiveArgumentError):
dec_3.update_vtpm(agentpool_2)

def common_update_fips_image(self):
dec_1 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{"enable_fips_image": True, "disable_fips_image": False},
self.resource_type,
self.agentpool_decorator_mode,
)
# fail on passing the wrong agentpool object
with self.assertRaises(CLIInternalError):
dec_1.update_fips_image(None)

agentpool_1 = self.create_initialized_agentpool_instance(enable_fips=False)
dec_1.context.attach_agentpool(agentpool_1)
dec_agentpool_1 = dec_1.update_fips_image(agentpool_1)
ground_truth_agentpool_1 = self.create_initialized_agentpool_instance(enable_fips=True)
self.assertEqual(dec_agentpool_1, ground_truth_agentpool_1)

dec_2 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{"enable_fips_image": False, "disable_fips_image": True},
self.resource_type,
self.agentpool_decorator_mode,
)
# fail on passing the wrong agentpool object
with self.assertRaises(CLIInternalError):
dec_2.update_fips_image(None)

agentpool_2 = self.create_initialized_agentpool_instance(enable_fips=True)
dec_2.context.attach_agentpool(agentpool_2)
dec_agentpool_2 = dec_2.update_fips_image(agentpool_2)
ground_truth_agentpool_2 = self.create_initialized_agentpool_instance(enable_fips=False)
self.assertEqual(dec_agentpool_2, ground_truth_agentpool_2)

# Should error if both set
dec_3 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{"enable_fips_image": True, "disable_fips_image": True},
self.resource_type,
self.agentpool_decorator_mode,
)
dec_3.context.attach_agentpool(agentpool_2)
with self.assertRaises(MutuallyExclusiveArgumentError):
dec_3.update_fips_image(agentpool_2)


class AKSPreviewAgentPoolUpdateDecoratorStandaloneModeTestCase(
AKSPreviewAgentPoolUpdateDecoratorCommonTestCase
Expand Down Expand Up @@ -1709,6 +1807,9 @@ def test_update_secure_boot(self):
def test_update_vtpm(self):
self.common_update_vtpm()

def test_update_fips_image(self):
self.common_update_fips_image()

def test_update_agentpool_profile_preview(self):
import inspect

Expand Down Expand Up @@ -1787,6 +1888,9 @@ def test_update_secure_boot(self):
def test_update_vtpm(self):
self.common_update_vtpm()

def test_update_fips_image(self):
self.common_update_fips_image()

def test_update_agentpool_profile_preview(self):
import inspect

Expand Down
103 changes: 103 additions & 0 deletions src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4645,6 +4645,109 @@ def test_aks_create_update_vtpm_flow(self, resource_group, resource_group_locati
checks=[self.is_empty()],
)

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="eastus2euap"
)
def test_aks_create_update_fips_flow(self, resource_group, resource_group_location):
# reset the count so in replay mode the random names will start with 0
self.test_resources_count = 0
aks_name = self.create_random_name("cliakstest", 16)
node_pool_name = self.create_random_name("c", 6)
node_pool_name_second = self.create_random_name("c", 6)
self.kwargs.update(
{
"resource_group": resource_group,
"name": aks_name,
"dns_name_prefix": self.create_random_name("cliaksdns", 16),
"location": resource_group_location,
"resource_type": "Microsoft.ContainerService/ManagedClusters",
"node_pool_name": node_pool_name,
"node_pool_name_second": node_pool_name_second,
"ssh_key_value": self.generate_ssh_keys(),
}
)

# 1. create
create_cmd = (
"aks create --resource-group={resource_group} --name={name} --location={location} "
"--nodepool-name {node_pool_name} -c 1 --enable-managed-identity "
"--ssh-key-value={ssh_key_value} "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview '
"--enable-fips-image"
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("agentPoolProfiles[0].enableFips", True),
],
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an update without either --enable-fips-image or --disable-fips-image, EnableFips should not change.

# verify same update no change
self.cmd(
"aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={node_pool_name} "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview '
"--enable-fips-image",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", True),
],
)

# update nodepool1 to disable
self.cmd(
"aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={node_pool_name} "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview '
"--disable-fips-image",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", False),
],
)

# 2. add nodepool2
self.cmd(
"aks nodepool add "
"--resource-group={resource_group} "
"--cluster-name={name} "
"--name={node_pool_name_second} "
"--os-type Linux "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview ',
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", False),
],
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an update without either --enable-fips-image or --disable-fips-image, EnableFips should not change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# verify same update no change
self.cmd(
"aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={node_pool_name_second} "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview '
"--disable-fips-image",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", False),
],
)

# update nodepool2 to enable
self.cmd(
"aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={node_pool_name_second} "
'--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/MutableFipsPreview '
"--enable-fips-image",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", True),
],
)

# delete
self.cmd(
"aks delete -g {resource_group} -n {name} --yes --no-wait",
checks=[self.is_empty()],
)

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="westus2"
Expand Down
6 changes: 6 additions & 0 deletions src/aks-preview/linter_exclusions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ aks nodepool update:
disable_vtpm:
rule_exclusions:
- option_length_too_long
enable_fips_image:
rule_exclusions:
- option_length_too_long
disable_fips_image:
rule_exclusions:
- option_length_too_long
aks nodepool delete:
parameters:
ignore_pod_disruption_budget:
Expand Down
2 changes: 1 addition & 1 deletion src/aks-preview/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from setuptools import setup, find_packages

VERSION = "5.0.0b2"
VERSION = "5.0.0b3"

CLASSIFIERS = [
"Development Status :: 4 - Beta",
Expand Down
Loading