File size: 7,252 Bytes
105b369
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
from typing import Optional, Any, Dict
from typing_extensions import Literal

from phi.aws.api_client import AwsApiClient
from phi.aws.resource.base import AwsResource
from phi.cli.console import print_info
from phi.utils.log import logger


class EksAddon(AwsResource):
    """
    Reference:
    - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/eks.html
    """

    resource_type: Optional[str] = "EksAddon"
    service_name: str = "eks"

    # Addon name
    name: str
    # EKS cluster name
    cluster_name: str
    # Addon version
    version: Optional[str] = None

    service_account_role_arn: Optional[str] = None
    resolve_conflicts: Optional[Literal["OVERWRITE", "NONE", "PRESERVE"]] = None
    client_request_token: Optional[str] = None
    tags: Optional[Dict[str, str]] = None

    preserve: Optional[bool] = False

    # provided by api on create
    created_at: Optional[str] = None
    status: Optional[str] = None

    wait_for_create: bool = False
    wait_for_delete: bool = False
    wait_for_update: bool = False

    def _create(self, aws_client: AwsApiClient) -> bool:
        """Creates the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        print_info(f"Creating {self.get_resource_type()}: {self.get_resource_name()}")

        # create a dict of args which are not null, otherwise aws type validation fails
        not_null_args: Dict[str, Any] = {}
        if self.version:
            not_null_args["addonVersion"] = self.version
        if self.service_account_role_arn:
            not_null_args["serviceAccountRoleArn"] = self.service_account_role_arn
        if self.resolve_conflicts:
            not_null_args["resolveConflicts"] = self.resolve_conflicts
        if self.client_request_token:
            not_null_args["clientRequestToken"] = self.client_request_token
        if self.tags:
            not_null_args["tags"] = self.tags

        # Step 1: Create EksAddon
        service_client = self.get_service_client(aws_client)
        try:
            create_response = service_client.create_addon(
                clusterName=self.cluster_name,
                addonName=self.name,
                **not_null_args,
            )
            logger.debug(f"EksAddon: {create_response}")
            # logger.debug(f"EksAddon type: {type(create_response)}")

            # Validate Cluster creation
            self.created_at = create_response.get("addon", {}).get("createdAt", None)
            self.status = create_response.get("addon", {}).get("status", None)
            logger.debug(f"created_at: {self.created_at}")
            logger.debug(f"status: {self.status}")
            if self.created_at is not None:
                print_info(f"EksAddon created: {self.name}")
                self.active_resource = create_response
                return True
        except service_client.exceptions.ResourceInUseException:
            print_info(f"Addon already exists: {self.name}")
            return True
        except Exception as e:
            logger.error(f"{self.get_resource_type()} could not be created.")
            logger.error(e)
        return False

    def post_create(self, aws_client: AwsApiClient) -> bool:
        # Wait for Addon to be created
        if self.wait_for_create:
            try:
                print_info(f"Waiting for {self.get_resource_type()} to be active.")
                waiter = self.get_service_client(aws_client).get_waiter("addon_active")
                waiter.wait(
                    clusterName=self.cluster_name,
                    addonName=self.name,
                    WaiterConfig={
                        "Delay": self.waiter_delay,
                        "MaxAttempts": self.waiter_max_attempts,
                    },
                )
            except Exception:
                # logger.error(f"Waiter failed: {awe}")
                pass
        return True

    def _read(self, aws_client: AwsApiClient) -> Optional[Any]:
        """Returns the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        from botocore.exceptions import ClientError

        logger.debug(f"Reading {self.get_resource_type()}: {self.get_resource_name()}")

        service_client = self.get_service_client(aws_client)
        try:
            describe_response = service_client.describe_addon(clusterName=self.cluster_name, addonName=self.name)
            # logger.debug(f"EksAddon: {describe_response}")
            # logger.debug(f"EksAddon type: {type(describe_response)}")
            addon_dict = describe_response.get("addon", {})

            self.created_at = addon_dict.get("createdAt", None)
            self.status = addon_dict.get("status", None)
            logger.debug(f"EksAddon created_at: {self.created_at}")
            logger.debug(f"EksAddon status: {self.status}")
            if self.created_at is not None:
                logger.debug(f"EksAddon found: {self.name}")
                self.active_resource = describe_response
        except ClientError as ce:
            logger.debug(f"ClientError: {ce}")
        except Exception as e:
            logger.error(f"Error reading {self.get_resource_type()}.")
            logger.error(e)
        return self.active_resource

    def _delete(self, aws_client: AwsApiClient) -> bool:
        """Deletes the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        print_info(f"Deleting {self.get_resource_type()}: {self.get_resource_name()}")

        # create a dict of args which are not null, otherwise aws type validation fails
        not_null_args: Dict[str, Any] = {}
        if self.preserve:
            not_null_args["preserve"] = self.preserve

        # Step 1: Delete EksAddon
        service_client = self.get_service_client(aws_client)
        self.active_resource = None
        try:
            delete_response = service_client.delete_addon(
                clusterName=self.cluster_name, addonName=self.name, **not_null_args
            )
            logger.debug(f"EksAddon: {delete_response}")
            # logger.debug(f"EksAddon type: {type(delete_response)}")
            return True
        except Exception as e:
            logger.error(f"{self.get_resource_type()} could not be deleted.")
            logger.error("Please try again or delete resources manually.")
            logger.error(e)
        return False

    def post_delete(self, aws_client: AwsApiClient) -> bool:
        # Wait for Addon to be deleted
        if self.wait_for_delete:
            try:
                print_info(f"Waiting for {self.get_resource_type()} to be deleted.")
                waiter = self.get_service_client(aws_client).get_waiter("addon_deleted")
                waiter.wait(
                    clusterName=self.cluster_name,
                    addonName=self.name,
                    WaiterConfig={
                        "Delay": self.waiter_delay,
                        "MaxAttempts": self.waiter_max_attempts,
                    },
                )
            except Exception as awe:
                logger.error(f"Waiter failed: {awe}")
        return True