Coverage for awsutils / aws_resource_operator.py: 89%
177 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-21 13:47 +0900
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-21 13:47 +0900
1# -*- config: utf8 -*-
2'''AwsResourceOperator module.
4Copyright ycookjp
5https://github.com/ycookjp/
7'''
9import boto3
10import logging
12class AwsResourceOperator:
13 '''Base class for operating AWS resource.
15 '''
16 def get_status(self, resource_id: str):
17 '''Gets resource status.
19 Args:
20 resource_id (str): Resource id.
22 Returns:
23 Returns resource status.
25 '''
26 pass
28 def _get_client(self, service_name: str, region_name: str,
29 access_key_id: str=None, secret_access_key: str=None):
30 '''Gets boto3 client.
32 Args:
33 seervice_name (str): service name such as ec2, rds ...
34 aws_access_key_id (str): access key id.
35 aws_secret_access_key (str): secret access key.
36 region_name (str): region name.
38 Returns:
39 Returns boto3's client instance.
41 '''
42 client = boto3.client(service_name, aws_access_key_id=access_key_id,
43 aws_secret_access_key=secret_access_key, region_name=region_name)
45 return client
47 def start(self, instance_id: str):
48 '''Starts AWS service instance.
50 Starts AWS service instance. This method is a abstruct method.
52 Args:
53 instance_id (str): Instance ID.
55 Returns:
56 Number of started instance(s).
58 Raises:
59 Exception: Raises exception if fail to start service instance.
61 '''
62 pass
64 def start_resources(self, instance_ids: list):
65 '''Starts AWS resources.
67 Starts AWS resources. This method is a abstruct method.
69 Args:
70 instance_ids (str ...): Instance IDs
72 Returns:
73 Number of started instance(s).
75 Raises:
76 Exception: Raises exception if fail to start service instance
77 at latest time.
79 '''
80 pass
82 def stop(self, instance_id: str):
83 '''Stops AWS resource instance.
85 Stops AWS resource instance. This method is a abstruct method.
87 Args:
88 instance_id (str): Instance ID
90 Returns:
91 Number of stopped instance(s).
93 Raises:
94 Exception: Raises exception if fail to stop service instance.
96 '''
97 pass
99 def stop_resources(self, instance_ids: list):
100 '''Stops AWS resources.
102 Stops AWS resources. This method is a abstruct method.
104 Args:
105 instance_ids (str ...): Instance IDs
107 Returns:
108 Number of stopped instance(s).
110 Raises:
111 Exception: Raises exception if fail to stop service instance
112 at latest time.
114 '''
115 pass
117class AwsEc2InstanceOperator(AwsResourceOperator):
118 '''Operator class for EC2 instance.
120 '''
121 _client = None
122 '''Boto3 ec2 client.
123 '''
125 def __init__(self, region_name: str, access_key_id: str=None,
126 secret_access_key: str=None):
127 '''Constructor.
129 Sets boto3 ec2 client to _client field.
131 Args:
132 region_name (str): regian name.
133 access_key_id (str, optional): access key id.
134 secret_access_key (str, optional): secret access key.
136 '''
137 self._client = self._get_client('ec2', region_name, access_key_id,
138 secret_access_key)
140 def get_status(self, ec2_instance_id: str):
141 '''Gets EC2 instance status.
143 Args:
144 ec2_instance_id (str): EC2 instance id.
146 Returns:
147 Returns EC2 instance id status name.
148 Status name is one of 'pending', 'running', 'shutting-down',
149 'terminated', 'stopping', 'stopped'.
151 '''
152 response = self._client.describe_instance_status(InstanceIds=[ec2_instance_id])
154 status = None
155 if len(response['InstanceStatuses']) > 0:
156 status = response['InstanceStatuses'][0]['InstanceState']['Name']
158 return status
160 def start(self, instance_id: str):
161 '''Starts EC2 instance.
163 Args:
164 instance_id (str): EC2 instance id.
166 Returns:
167 Number of started instance(s).
169 Raises:
170 Exception: Raises exception if fail to start EC2 instance.
172 '''
173 count = 0
175 self._client.start_instances(InstanceIds=[instance_id])
176 count = count + 1
177 logging.info(f'ec2: \'{instance_id}\' starting ...')
179 return count
181 def start_resources(self, instance_ids: list):
182 '''Starts EC2 instances.
184 Args:
185 instance_ids (str ...): EC2 instance IDs
187 Returns:
188 Number of started instance(s).
190 Raises:
191 Exception: raises exception if fail to start EC2 instance
192 at latest time.
194 '''
195 count = 0
196 error = None
198 for instance_id in instance_ids:
199 try:
200 result = self.start(instance_id)
201 count = count + result
202 except Exception as e:
203 error = e
205 if error != None:
206 raise error
208 return count
210 def stop(self, instance_id: str):
211 '''Stops EC2 instance.
213 Args:
214 instance_id (str): EC2 instance ID.
216 Returns:
217 Number of stopped instance(s).
219 Raises:
220 Exception: Raises exception if fail to stop EC2 instance.
222 '''
223 count = 0
225 self._client.stop_instances(InstanceIds=[instance_id])
226 count = count + 1
227 logging.info(f'ec2: \'{instance_id}\' stopping ...')
229 return count
231 def stop_resources(self, instance_ids: list):
232 '''Stops EC2 instances.
234 Args:
235 instance_ids (str ...): EC2 instance IDs.
237 Returns:
238 Number of stopped instance(s).
240 Raises:
241 Exception: Raises exception if fail to stop EC2 instance
242 at latest time.
244 '''
245 count = 0
246 error = None
248 for instance_id in instance_ids:
249 try:
250 result = self.stop(instance_id)
251 count = count + result
252 except Exception as e:
253 error = e
255 if error != None:
256 raise error
258 return count
260class AwsRdsDbClusterOperator(AwsResourceOperator):
261 '''Operator class for RDS DB cluster.
263 '''
264 _client = None
265 '''Boto3 rds client.
266 '''
268 def __init__(self, region_name: str, access_key_id: str=None,
269 secret_access_key: str=None):
270 '''Constructor.
272 Sets boto3 rds client to _client field.
274 Args:
275 region_name (str): regian name.
276 access_key_id (str, optional): access key id.
277 secret_access_key (str, optional): secret access key.
279 '''
280 self._client = self._get_client('rds', region_name, access_key_id,
281 secret_access_key)
283 def get_status(self, db_cluster_id: str):
284 '''Gets RDS DB cluster status.
286 Args:
287 db_cluster_id (str): RDS DB cluster id.
289 Returns:
290 Returns RDS DB cluster status name.
291 Status name is on of 'available', 'backing-up', 'backtracking',
292 'cloning-failed', 'creating', 'deleting', 'failing-over',
293 'inaccessible-encryption-credentials'.
294 'inaccessible-encryption-credentials-recoverable', 'maintenance',
295 'migrating', 'migration-failed', 'modifying', 'promoting',
296 'renaming', 'resetting-master-credentials', 'starting', 'stopped',
297 'stopping', 'storage-optimization', 'update-iam-db-auth',
298 'upgrading'.
300 '''
301 response = self._client.describe_db_clusters(DBClusterIdentifier=db_cluster_id)
303 status = None
304 if len(response['DBClusters']) > 0: 304 ↛ 307line 304 didn't jump to line 307 because the condition on line 304 was always true
305 status = response['DBClusters'][0]['Status']
307 return status
309 def start(self, instance_id: str):
310 '''Starts RDS DB cluster.
312 If RDS DB cluster status is 'stopped', then starts RDS DB cluster.
313 Else do nothing.
315 Args:
316 instance_id (str): RDS DB cluster ID.
318 Returns:
319 Number of started cluster(s).
321 Raises:
322 Exception: Raises exception if fail to start RDS cluster.
324 '''
325 count = 0
326 status = self.get_status(instance_id)
328 # starts cluster instance only if status is stopped
329 if status == 'stopped':
330 self._client.start_db_cluster(DBClusterIdentifier=instance_id)
331 count = count + 1
332 logging.info(f'RDS DB cluster: \'{instance_id}\' starting ...')
334 return count
336 def start_resources(self, instance_ids: list):
337 '''Starts RDS DB clusters.
339 If RDS DB cluster status is 'stopped', then starts RDS DB cluster.
340 Else do nothing.
342 Args:
343 instance_ids (list): RDS DB cluster IDs
345 Returns:
346 Number of started cluster(s).
348 Raises:
349 Exception: Raises exception if fail to start RDS cluster at
350 latest time.
352 '''
353 count = 0
354 error = None
356 for instance_id in instance_ids:
357 try:
358 result = self.start(instance_id)
359 count = count + result
360 except Exception as e:
361 error = e
363 if error != None:
364 raise error
366 return count
368 def stop(self, instance_id: str):
369 '''Stops RDS DB cluster.
371 If RDS DB instance status is 'available', then stops RDS DB instance.
372 Else do nothing.
374 Args:
375 instance_id (str): RDS DB cluster ID.
377 Returns:
378 Number of stopped RDS DB cluster.
380 Raises:
381 Exception: Raises exception if fail to stop RDS cluster.
383 '''
384 count = 0
385 status = self.get_status(instance_id)
387 # Stops cluster instance only if status is available
388 if status == 'available':
389 self._client.stop_db_cluster(DBClusterIdentifier=instance_id)
390 count = count + 1
391 logging.info(f'RDS DB cluster: \'{instance_id}\' stopping ...')
393 return count
395 def stop_resources(self, instance_ids: list):
396 '''Stops RDS DB clusters.
398 If RDS DB instance status is 'available', then stops RDS DB instance.
399 Else do nothing.
401 Args:
402 instance_ids (str ...): RDS DB cluster IDs.
404 Returns:
405 Number of stopped RDS DB cluster(s).
407 Raises:
408 Exception: Raises exception if fail to stop RDS cluster at latest time.
410 '''
411 count = 0
412 error = None
414 for instance_id in instance_ids:
415 try:
416 result = self.stop(instance_id)
417 count = count + result
418 except Exception as e:
419 error = e
421 if error != None:
422 raise error
424 return count
426class AwsRdsDbInstanceOperator(AwsResourceOperator):
427 '''Operator class for RDS instance.
429 '''
430 _client = None
431 '''Boto3 rds client.
432 '''
434 def __init__(self, region_name: str, access_key_id: str=None,
435 secret_access_key: str=None):
436 '''Constructor.
438 Sets boto3 rds client to _client instance variable.
440 Args:
441 region_name (str): regian name.
442 access_key_id (str, optional): access key id.
443 secret_access_key (str, optional): secret access key.
445 '''
446 self._client = self._get_client('rds', region_name,access_key_id,
447 secret_access_key)
449 def get_status(self, db_instance_id: str):
450 '''Gets RDS DB instance status.
452 Args:
453 db_instance_id (str): RDS DB instance id.
455 Returns:
456 Returns RDS DB instance status name.
457 Status name is one of 'available', 'backing-up',
458 'configuring-enhanced-monitoring', 'configuring-iam-database-auth',
459 'configuring-log-exports', 'converting-to-vpc', 'creating',
460 'deleting', 'failed', 'inaccessible-encryption-credentials',
461 'inaccessible-encryption-credentials-recoverable',
462 'incompatible-network', 'incompatible-option-group',
463 'incompatible-parameters', 'incompatible-restore',
464 'insufficient-capacity', 'maintenance', 'modifying',
465 'moving-to-vpc', 'rebooting', 'resetting-master-credentials',
466 'renaming', 'restore-error', 'starting', 'stopped', 'stopping',
467 'storage-full', 'storage-optimization', 'upgrading'.
469 '''
470 response = self._client.describe_db_instances(DBInstanceIdentifier=db_instance_id)
472 status = None
473 if len(response['DBInstances']) > 0: 473 ↛ 476line 473 didn't jump to line 476 because the condition on line 473 was always true
474 status = response['DBInstances'][0]['DBInstanceStatus']
476 return status
478 def start(self, instance_id: str):
479 '''Starts RDS DB instance.
481 If RDS DB instance status is stopped, then starts RDS DB instance.
482 Else do nothing.
484 Args:
485 instance_id (str): RDS DB instance ID.
487 Returns:
488 Number of started instance(s).
490 Raises:
491 Exception: Raises exception if fail to start RDS instance.
493 '''
494 count = 0
495 status = self.get_status(instance_id)
497 # starts cluster instance only if status is stopped
498 if status == 'stopped':
499 self._client.start_db_instance(DBInstanceIdentifier=instance_id)
500 count = count + 1
501 logging.info(f'RDS instance: \'{instance_id}\' starting ...')
503 return count
505 def start_resources(self, instance_ids: list):
506 '''Starts RDS DB instances.
508 If RDS DB instance status is stopped, then starts RDS DB instance.
509 Else do nothing.
511 Args:
512 instance_ids (list): RDS DB instance IDs
514 Returns:
515 Number of started instance(s).
517 Raises:
518 Exception: Raises exception if fail to start RDS DB instance
519 at latest time.
521 '''
522 count = 0
523 error = None
525 for instance_id in instance_ids:
526 try:
527 result = self.start(instance_id)
528 count = count + result
529 except Exception as e:
530 error = e
532 if error != None:
533 raise error
535 return count
537 def stop(self, instance_id: str):
538 '''Stops RDS DB instance.
540 If RDS DB instance status is available, then stops RDS DB instance.
541 Else do nothing.
543 Args:
544 instance_id (str): RDS DB instance ID.
546 Returns:
547 Number of stopped instance(s).
549 Raises:
550 Exception: Raises exception if fail to stop RDS DB instance.
552 '''
553 count = 0
554 status = self.get_status(instance_id)
556 # starts cluster instance only if status is available
557 if status == 'available':
558 self._client.stop_db_instance(DBInstanceIdentifier=instance_id)
559 count = count + 1
560 logging.info(f'RDS instance: \'{instance_id}\' stopping ...')
562 return count
564 def stop_resources(self, instance_ids: list):
565 '''Stops RDS DB instances.
567 If RDS DB instance status is available, then stops RDS DB instance.
568 Else do nothing.
570 Args:
571 instance_ids (str ...): RDS instance IDs.
573 Returns:
574 Number of stopped instance(s).
576 Raises:
577 Exception: Raises exception if fail to stop RDS DB instance
578 at latest time.
580 '''
581 count = 0
582 error = None
584 for instance_id in instance_ids:
585 try:
586 result = self.stop(instance_id)
587 count = count + result
588 except Exception as e:
589 error = e
591 if error != None:
592 raise error
594 return count
596class AwsResourceOperatorFactory:
597 '''Factory class for generating AwsResourceOperator instance.
599 '''
601 @staticmethod
602 def create(resource_type: str, region_name: str,
603 access_key_id: str=None, secret_access_key: str=None):
604 '''Creates AWS instance operator's instance.
606 Args:
607 service_name (str): AWS service name. Available service names
608 are followings things.
609 - ec2.instance
610 - rds.db_cluster
611 - rds.db_instance
613 Returns:
614 AwsResourceOperator: Returns created AWS instance operator's
615 instance.
617 Raises:
618 RuntimeError: If service_name is incorrect.
620 '''
622 operator: AwsResourceOperator = None
624 if resource_type == 'ec2.instance':
625 operator = AwsEc2InstanceOperator(
626 region_name, access_key_id, secret_access_key)
627 elif resource_type == 'rds.db_cluster':
628 operator = AwsRdsDbClusterOperator(
629 region_name, access_key_id,secret_access_key)
630 elif resource_type == 'rds.db_instance':
631 operator = AwsRdsDbInstanceOperator(
632 region_name, access_key_id,secret_access_key)
633 else:
634 raise RuntimeError(f'Cloud not create AwsResourceOperator class from class name:{resource_type}')
636 return operator