Skip to content
Open
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
120 changes: 120 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
.idea/
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
media/

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
.Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# poetry dependency management
poetry.lock
25 changes: 25 additions & 0 deletions Constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from enum import Enum


class Prefix(Enum):
ALLOWED = ['*']
RESTRICTED = ['prod']


class StatusCodes(Enum):
SUCCESS_STATUS_CODE = 200
ERROR_STATUS_CODE = 500


class ServiceState(Enum):
RUNNING = "Running"
PENDING = "Pending"
CHECKING = "Checking"
SERVICE_NOT_FOUND = "Service not found"


class Operations(Enum):
GET_STATUS = "status"
UPDATE_SERVICE = "update"


29 changes: 29 additions & 0 deletions EcsClusterProcessor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from EcsManage import ECSManager
from Constants import Operations
from utils import build_response
from Constants import StatusCodes


class ClusterProcessor:
def __init__(self, ecs_manager):
self.ecs_manager:ECSManager = ECSManager()

def process_clusters(self, cluster_names, environments, desired_tasks,operation:Operations=Operations.GET_STATUS):
"""Process ECS clusters."""
cluster_arns = self.ecs_manager.get_all_clusters_arns()
response = []
for cluster_name in cluster_names:
for cluster_arn in cluster_arns:
if self.should_process_cluster(cluster_name, cluster_arn, environments):
if operation == Operations.UPDATE_SERVICE:
self.ecs_manager.update_cluster_services(cluster_arn, desired_tasks)
response = build_response(StatusCodes.SUCCESS_STATUS_CODE,f"Successfully update {cluster_name}")
elif operation == Operations.GET_STATUS:
response.append(self.ecs_manager.check_status(cluster_arn))
return response

@staticmethod
def should_process_cluster(cluster_name, cluster_arn, environments):
"""Check if the cluster should be processed."""
return (cluster_name == "all" or cluster_name in cluster_arn) and any(env in cluster_arn for env in environments) and cluster_name and cluster_arn

80 changes: 80 additions & 0 deletions EcsManage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import json
import os
import boto3
from Constants import (Prefix)
from utils import (build_response,
get_name_from_arn,
build_service_status)


class ECSManager:
def __init__(self):
self.ecs_client = self._get_ecs_client()

@staticmethod
def _get_ecs_client():
region = os.environ.get("AWS_REGION")
return boto3.client('ecs', region_name=region)

@staticmethod
def _contains_restricted(arn):
for restricted in Prefix.RESTRICTED.value:
return restricted.lower() in arn.lower()

def remove_restricted_arns(self, arn_list):
return [arn for arn in arn_list if not self._contains_restricted(arn)]

def get_all_clusters_arns(self):
try:
response = self.ecs_client.list_clusters()
return self.remove_restricted_arns(response["clusterArns"])
except Exception as e:
print(e)
return self._error_response(str(e))

def get_all_services_arns(self, cluster):
try:
response = self.ecs_client.list_services(cluster=cluster)
return response["serviceArns"]
except Exception as e:
print(e)
return self._error_response(str(e))

def update_ecs_service(self, desired_task, cluster, service):
if self._contains_restricted(cluster):
raise Exception("Operation on this clusters is restricted")
self.ecs_client.update_service(cluster=cluster, service=service, desiredCount=int(desired_task))
cluster_name = get_name_from_arn(cluster)
service_name = get_name_from_arn(service)
print("Service updated successfully:", {"cluster": cluster_name, "service": service_name})

def update_cluster_services(self, cluster_arn, desired_tasks):
"""Update services in the cluster."""
service_arns = self.get_all_services_arns(cluster=cluster_arn)
for service_arn in service_arns:
self.update_ecs_service(desired_task=desired_tasks, cluster=cluster_arn, service=service_arn)

def check_status(self,cluster):
services = self.get_all_services_arns(cluster)
response = self.ecs_client.describe_services(
cluster=cluster,
services=services
)
cluster_name = get_name_from_arn(cluster)
cluster_status = {"cluster": cluster_name, "services":[]}
if 'services' in response and len(response['services']) > 0:
for service in response['services']:
service_name = service.get('serviceName','')
running_count = service.get('runningCount', 0)
pending_count = service.get('pendingCount', 0)
cluster_status['services'].append(build_service_status(
service=service_name,
running=running_count,
pending=pending_count
))
print("serivce name: ",service_name,", running: ",running_count,", pending: ",pending_count)
return cluster_status

@staticmethod
def _error_response(message):
return build_response(500, message)
93 changes: 0 additions & 93 deletions EcsUpdate.py

This file was deleted.

Loading