108 lines
3.2 KiB
Python
108 lines
3.2 KiB
Python
import logging
|
|
import typing
|
|
|
|
import boto3
|
|
import botocore.client
|
|
|
|
|
|
def paginate_by_marker(
|
|
func: callable,
|
|
list_field: str,
|
|
) -> typing.Iterable:
|
|
"""
|
|
Simplifies paginating over AWS results with a simpler interface than Paginators.
|
|
:param func: A function that accepts a parameter named `Marker`
|
|
:param list_field: Result field to iterate on
|
|
"""
|
|
marker = ""
|
|
while True:
|
|
result = func(Marker=marker)
|
|
|
|
items = result.get(list_field, [])
|
|
yield from items
|
|
|
|
if "Marker" not in result:
|
|
break
|
|
|
|
marker = result["Marker"]
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Rediser:
|
|
@classmethod
|
|
def new(cls):
|
|
return cls(boto3.client("elasticache", region_name='eu-central-1'))
|
|
|
|
def __init__(self, elasticache: botocore.client.BaseClient):
|
|
self.elasticache = elasticache
|
|
|
|
def _get_redis_acl(
|
|
self,
|
|
cluster_id: str = None,
|
|
status: str = "available",
|
|
) -> typing.Optional[dict]:
|
|
"""
|
|
Finds a Redis replication group by its ID
|
|
|
|
:param cluster_id: Replication group ID
|
|
:param status: Replication status. One of available/starting/modifying/deleting.
|
|
:return: RedisInstance or throws LookupError error
|
|
"""
|
|
try:
|
|
redis = self.elasticache.describe_replication_groups(ReplicationGroupId=cluster_id)["ReplicationGroups"][0]
|
|
if redis["Status"] != status:
|
|
raise Exception(f"Found redis with {cluster_id=} but its status={redis['Status']}")
|
|
except self.elasticache.exceptions.ReplicationGroupNotFoundFault:
|
|
return None
|
|
|
|
return dict(
|
|
cluster_id=redis["ReplicationGroupId"],
|
|
host=redis["NodeGroups"][0]["PrimaryEndpoint"]["Address"],
|
|
port=redis["NodeGroups"][0]["PrimaryEndpoint"]["Port"],
|
|
arn=redis["ARN"],
|
|
user_group_ids=redis["UserGroupIds"],
|
|
)
|
|
|
|
def create_redis_acl(
|
|
self,
|
|
*,
|
|
cluster_id: str,
|
|
cluster_description: typing.Optional[str] = None,
|
|
node_type: str,
|
|
subnet_group_name: str,
|
|
security_group_id: str,
|
|
):
|
|
redis = self._get_redis_acl(cluster_id=cluster_id)
|
|
|
|
if not redis:
|
|
res = self.elasticache.create_replication_group(
|
|
ReplicationGroupId=cluster_id,
|
|
ReplicationGroupDescription=cluster_description or cluster_id,
|
|
ReplicasPerNodeGroup=0,
|
|
Engine="redis",
|
|
EngineVersion="6.x",
|
|
CacheNodeType=node_type,
|
|
CacheSubnetGroupName=subnet_group_name,
|
|
TransitEncryptionEnabled=True, # must be True to use Redis ACL
|
|
UserGroupIds=[
|
|
user_group_id,
|
|
],
|
|
SecurityGroupIds=[
|
|
security_group_id,
|
|
],
|
|
Tags=[{"Key": k, "Value": v} for k, v in tags.items()],
|
|
MultiAZEnabled=False,
|
|
AutomaticFailoverEnabled=False,
|
|
)
|
|
|
|
|
|
def main():
|
|
r = Rediser.new()
|
|
res = r.create_redis_acl(cluster_id='hey', node_type='cache.t2.micro')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|