Source code for idem_aws.states.aws.eks.addon

"""State module for managing EKS Addon."""
import copy
from dataclasses import field
from dataclasses import make_dataclass
from typing import Any
from typing import Dict

__contracts__ = ["resource"]

TREQ = {
    "absent": {
        "require": [
            "aws.ec2.subnet.absent",
            "aws.iam.role.absent",
            "aws.iam.role_policy_attachment.absent",
            "aws.eks.cluster.absent",
        ],
    },
    "present": {
        "require": [
            "aws.ec2.subnet.present",
            "aws.iam.role.present",
            "aws.iam.role_policy_attachment.present",
            "aws.eks.cluster.present",
        ],
    },
}


[docs]async def present( hub, ctx, name: str, cluster_name: str, addon_version: str, resource_id: str = None, service_account_role_arn: str = None, resolve_conflicts: str = "OVERWRITE", tags: Dict[str, str] = None, timeout: make_dataclass( "Timeout", [ ( "create", make_dataclass( "CreateTimeout", [ ("delay", int, field(default=10)), ("max_attempts", int, field(default=60)), ], ), field(default=None), ), ( "update", make_dataclass( "UpdateTimeout", [ ("delay", int, field(default=10)), ("max_attempts", int, field(default=60)), ], ), field(default=None), ), ], ) = None, ) -> Dict[str, Any]: """Creates an Amazon EKS add-on. Amazon EKS add-ons help to automate the provisioning and lifecycle management of common operational software for Amazon EKS clusters. Amazon EKS add-ons require clusters running version 1.18 or because Amazon EKS add-ons rely on the Server-side Apply Kubernetes feature, which is only available in Kubernetes 1.18 and later. For more information, see Amazon EKS add-ons in the Amazon EKS User Guide. Args: name(str): An Idem name of the EKS addon resource. resource_id(str, Optional): AWS EKS addon name. cluster_name(str): The name of the cluster to create the add-on for addon_version(str): The version of the add-on. The version must match one of the versions returned by ` DescribeAddonVersions service_account_role_arn(str, Optional): The Amazon Resource Name (ARN) of an existing IAM role to bind to the add-on's service account. The role must be assigned the IAM permissions required by the add-on. If you don't specify an existing IAM role, then the add-on uses the permissions assigned to the node IAM role. resolve_conflicts(str, Optional): How to resolve parameter value conflicts when migrating an existing add-on to an Amazon EKS add-on tags(dict, Optional): The metadata to apply to the cluster to assist with categorization and organization. Each tag consists of a key and an Optional value. You define both timeout(dict, Optional): Timeout configuration for creating or updating addon. * create (dict): Timeout configuration for creating addon * delay(int, default=10): The amount of time in seconds to wait between attempts. * max_attempts(int, default=60): Customized timeout configuration containing delay and max attempts. * update (str): Timeout configuration for updating addon * delay(int, default=10): The amount of time in seconds to wait between attempts. * max_attempts(int, default=60): Customized timeout configuration containing delay and max attempts. Request Syntax: .. code-block:: sls [eks-addon-name]: aws.eks.addon.present: - cluster_name: 'string' - addon_version: 'string' - resource_id: 'string' - service_account_role_arn: 'string' - resolve_conflicts: 'string' - tags: - 'string': 'string' - timeout: create: delay: 'integer' max_attempts: 'integer' update: delay: 'integer' max_attempts: 'integer Returns: Dict[str, Any] Examples: .. code-block:: sls kube-proxy: aws.eks.addon.present: - cluster_name: eks-12j44i4k - addon_version: v1.19.8-eksbuild.1 - resource_id: kube-proxy - service_account_role_arn: arn:role-ejwew124 - resolve_conflicts: "OVERWRITE" - tags: - Name: eks-addon-name """ result = dict(comment=[], old_state=None, new_state=None, name=name, result=True) before = None resource_updated = False if resource_id: before = await hub.exec.boto3.client.eks.describe_addon( ctx, clusterName=cluster_name, addonName=name ) if not before["result"]: if not ("ResourceNotFoundException" in before["comment"][0]): result["result"] = False result["comment"] = before["comment"] return result if before and before["ret"]: try: result[ "old_state" ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present( raw_resource=before["ret"]["addon"], idem_resource_name=name ) plan_state = copy.deepcopy(result["old_state"]) client_request_token = result["old_state"].get("client_request_token", None) update_ret = await hub.tool.aws.eks.addon.update_addon( ctx=ctx, name=name, before=result["old_state"], addon_version=addon_version, service_account_role_arn=service_account_role_arn, resolve_conflicts=resolve_conflicts, client_request_token=client_request_token, timeout=timeout, ) result["comment"] = update_ret["comment"] result["result"] = update_ret["result"] resource_updated = bool(update_ret["ret"]) if update_ret["ret"] and ctx.get("test", False): result["comment"] += [f"Would update aws.eks.addon '{name}'"] for addon_param in update_ret["ret"]: plan_state[addon_param] = update_ret["ret"][addon_param] if tags is not None: # Update tags update_tags_ret = await hub.tool.aws.eks.tag.update_eks_tags( ctx=ctx, resource_arn=result["old_state"].get("addon_arn"), old_tags=result["old_state"].get("tags"), new_tags=tags, ) result["comment"] += update_tags_ret["comment"] result["result"] = result["result"] and update_tags_ret["result"] resource_updated = resource_updated or bool(update_tags_ret["ret"]) if ctx.get("test", False) and update_tags_ret["ret"]: plan_state["tags"] = update_tags_ret["ret"].get("tags") except hub.tool.boto3.exception.ClientError as e: result["comment"] += [f"{e.__class__.__name__}: {e}"] result["result"] = False else: if ctx.get("test", False): result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state( enforced_state={}, desired_state={ "name": name, "cluster_name": cluster_name, "addon_version": addon_version, "service_account_role_arn": service_account_role_arn, "resolve_conflicts": resolve_conflicts, "tags": tags, }, ) result["comment"] = hub.tool.aws.comment_utils.would_create_comment( resource_type="aws.eks.addon", name=name ) return result try: ret = await hub.exec.boto3.client.eks.create_addon( ctx, clusterName=cluster_name, addonName=name, addonVersion=addon_version, serviceAccountRoleArn=service_account_role_arn, resolveConflicts=resolve_conflicts, tags=tags, ) result["result"] = ret["result"] if not result["result"]: result["comment"] = ret["comment"] return result resource_id = ret["ret"]["addon"]["addonName"] waiter_config = hub.tool.aws.waiter_utils.create_waiter_config( default_delay=60, default_max_attempts=40, timeout_config=timeout.get("create") if timeout else None, ) hub.log.debug(f"Waiting on creating aws.eks.addon '{name}'") try: await hub.tool.boto3.client.wait( ctx, "eks", "addon_active", addonName=resource_id, clusterName=cluster_name, WaiterConfig=waiter_config, ) except Exception as e: result["comment"] += [str(e)] result["result"] = False result["comment"] = hub.tool.aws.comment_utils.create_comment( resource_type="aws.eks.addon", name=name ) except Exception as e: result["comment"] += [f"{e.__class__.__name__}: {e}"] result["result"] = False return result try: if ctx.get("test", False): result["new_state"] = plan_state elif (not before) or resource_updated: after = await hub.exec.boto3.client.eks.describe_addon( ctx, clusterName=cluster_name, addonName=resource_id ) result[ "new_state" ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present( raw_resource=after["ret"]["addon"], idem_resource_name=name ) else: result["new_state"] = copy.deepcopy(result["old_state"]) except Exception as e: result["comment"] += [str(e)] result["result"] = False return result
[docs]async def absent( hub, ctx, name: str, cluster_name: str = None, resource_id: str = None, preserve: bool = False, timeout: Dict = None, ) -> Dict[str, Any]: """ Delete an Amazon EKS add-on. When you remove the add-on, it will also be deleted from the cluster. You can always manually start an add-on on the cluster using the Kubernetes API. Args: name(str): An Idem name of the EKS addon resource. cluster_name(str, Optional): The name of the cluster to delete the add-on from. resource_id(str, Optional): AWS EKS addon name. Idem automatically considers this resource being absent if this field is not specified. preserve(bool, Optional): Specifying this option preserves the add-on software on your cluster but Amazon EKS stops managing any settings for the add-on. If an IAM account is associated with the add-on, it is not removed. timeout(dict, Optional): Timeout configuration for creating or updating cluster. * delete (dict): Timeout configuration for deleting cluster * delay: The amount of time in seconds to wait between attempts. * max_attempts: Customized timeout configuration containing delay and max attempts. Request syntax: .. code-block:: sls [idem-eks-addon-name]: aws.eks.addon.absent: - cluster_name: 'string' - resource_id: 'string' - preserve: bool Returns: Dict[str, Any] Examples: .. code-block:: sls kube-proxy: aws.eks.addon.absent: - cluster_name: eks-cluster-1 - resource_id: kube-proxy - preserve: True """ result = dict(comment=[], old_state=None, new_state=None, name=name, result=True) if not resource_id: result["comment"] = hub.tool.aws.comment_utils.already_absent_comment( resource_type="aws.eks.addon", name=name ) return result if not cluster_name: result["comment"] = hub.tool.aws.comment_utils.missing_args_for_absent_comment( resource_type="aws.eks.addon", name=name, args=["cluster_name"] ) result["result"] = False return result before = await hub.exec.boto3.client.eks.describe_addon( ctx, clusterName=cluster_name, addonName=resource_id ) if not before["ret"]: result["comment"] = hub.tool.aws.comment_utils.already_absent_comment( resource_type="aws.eks.addon", name=name ) elif ctx.get("test", False): result[ "old_state" ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present( raw_resource=before["ret"]["addon"], idem_resource_name=name ) result["comment"] = hub.tool.aws.comment_utils.would_delete_comment( resource_type="aws.eks.addon", name=name ) return result else: result[ "old_state" ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present( raw_resource=before["ret"]["addon"], idem_resource_name=name ) try: ret = await hub.exec.boto3.client.eks.delete_addon( ctx, clusterName=cluster_name, addonName=resource_id, preserve=preserve ) result["result"] = ret["result"] if not result["result"]: result["comment"] = ret["comment"] result["result"] = False return result else: waiter_config = hub.tool.aws.waiter_utils.create_waiter_config( default_delay=60, default_max_attempts=40, timeout_config=timeout.get("delete") if timeout else None, ) try: await hub.tool.boto3.client.wait( ctx, "eks", "addon_deleted", addonName=resource_id, clusterName=cluster_name, WaiterConfig=waiter_config, ) except Exception as e: result["comment"] += [str(e)] result["result"] = False result["comment"] = result[ "comment" ] + hub.tool.aws.comment_utils.delete_comment( resource_type="aws.eks.addon", name=name ) except hub.tool.boto3.exception.ClientError as e: result["comment"] += [f"{e.__class__.__name__}: {e}"] return result
[docs]async def describe(hub, ctx) -> Dict[str, Dict[str, Any]]: """ Describe the resource in a way that can be recreated/managed with the corresponding "present" function Lists the available add-ons. Returns: Dict[str, Any] Examples: .. code-block:: bash $ idem describe aws.eks.addon """ result = {} cluster_ret = await hub.exec.boto3.client.eks.list_clusters(ctx) if not cluster_ret["result"]: hub.log.warning(f"Could not describe cluster {cluster_ret['comment']}") return {} cluster_addons = [] try: for name in cluster_ret["ret"]["clusters"]: addon_ret = await hub.exec.boto3.client.eks.list_addons( ctx, clusterName=name ) if not addon_ret["result"]: hub.log.debug( f"Could not describe cluster addons for cluster {name}, Error: {addon_ret['comment']}" ) continue for addon in addon_ret["ret"]["addons"]: cluster_addons.append({"name": name, "addon": addon}) except Exception as e: result["comment"] = str(e) result["result"] = False return result for cluster_addon in cluster_addons: cluster_name = cluster_addon["name"] current_addon = cluster_addon["addon"] resource_id = f"{cluster_name}-{current_addon}" describe_ret = await hub.exec.boto3.client.eks.describe_addon( ctx, clusterName=cluster_name, addonName=current_addon ) if not describe_ret["result"] or not describe_ret["ret"]: hub.log.warning( f"Could not describe addon {name}, Error: {describe_ret['comment']}" ) continue add_on = describe_ret["ret"]["addon"] resource_translated = ( hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present( raw_resource=add_on, idem_resource_name=resource_id ) ) result[resource_id] = { "aws.eks.addon.present": [ {parameter_key: parameter_value} for parameter_key, parameter_value in resource_translated.items() ] } return result