def __init__(self, args): self.service_list = [] task_definition_config_json = render.load_json(args.task_definition_config_json) files = os.listdir(args.task_definition_template_dir) for file in files: try: task_definitions = render.render_definition(args.task_definition_template_dir, file, task_definition_config_json, args.task_definition_config_env) self.service_list.extend(self.import_service_from_task_definitions(task_definitions)) except: error("Template error. file: %s.\n%s" % (file, traceback.format_exc())) sys.exit(1) if args.deploy_service_group: self.deploy_service_list = list(filter(lambda service:service.task_environment.service_group == args.deploy_service_group, self.service_list)) else: self.deploy_service_list = self.service_list if len(self.deploy_service_list) == 0: error("Deployment target service is None.") sys.exit(1) self.ecs_service = ECSService(access_key=args.key, secret_key=args.secret, region=args.region) self.is_service_zero_keep = args.service_zero_keep self.environment = task_definition_config_json['environment'] self.template_group = args.template_group self.cluster_list = [] for service in self.service_list: if service.task_environment.cluster_name not in self.cluster_list: self.cluster_list.append(service.task_environment.cluster_name) self.error = False
def __init__(self, webhook_url, regions, message, tag_key, tag_value, lifetime_tag_key, behavior_type): self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) self.regions = regions self.behavior_type = behavior_type self.slack_service = slack.Slack.get_instance(webhook_url, message, tag_key, tag_value, lifetime_tag_key) self.ec2_service = EC2Service(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger) self.rds_service = RDSService(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger) self.ecs_service = ECSService(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger)
class AWSTerminator: def __init__(self, webhook_url, regions, message, tag_key, tag_value, lifetime_tag_key, behavior_type): self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) self.regions = regions self.behavior_type = behavior_type self.slack_service = slack.Slack.get_instance(webhook_url, message, tag_key, tag_value, lifetime_tag_key) self.ec2_service = EC2Service(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger) self.rds_service = RDSService(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger) self.ecs_service = ECSService(tag_key, tag_value, lifetime_tag_key, behavior_type, self.logger) def process(self): self.logger.info('Processing AWSTerminator...') for region in self.regions: self.logger.info('Processing AWSTerminator for %s...', region) self.slack_service.intro_text(region) # Boto3 setup by region self.ec2_service.set_boto3(region) self.rds_service.set_boto3(region) self.ecs_service.set_boto3(region) # Loop on services resources self.ec2_service.resources_loop(region) self.rds_service.resources_loop(region) self.ecs_service.resources_loop(region) # Process behavior self.slack_service.outro_text() self.behavior() self.slack_service.clean_blocks() self.logger.info('Process Done for %s.\n', region) def behavior(self): self.logger.info('Processing behavior %s...', self.behavior_type) if self.behavior_type == 'notify': self.slack_service.request() elif self.behavior_type == 'stop': self.ec2_service.stop_untagged_resources() self.rds_service.stop_untagged_resources() self.ecs_service.stop_untagged_resources() self.slack_service.request() elif self.behavior_type == 'terminate': self.ec2_service.terminate_untagged_resources() self.rds_service.terminate_untagged_resources() self.ecs_service.terminate_untagged_resources() self.slack_service.request() else: self.logger.info('%s behavior does not exist.', self.behavior_type)
parser.add_argument('--service-name', dest='service_name', required=False) parser.add_argument('--minimum-running-tasks', type=int, dest='minimum_running_tasks', default=1, required=False) args = parser.parse_args() try: serviceMode = args.service_name is not None # Step: Configuring AWS h1("Step: Configuring AWS") ecs = ECSService(access_key=args.key, secret_key=args.secret, region=args.region) success("Configuring AWS succeeded") # Step: Check ECS cluster h1("Step: Check ECS cluster") ecs.describe_cluster(cluster=args.cluster_name) success("Checking cluster '%s' succeeded" % args.cluster_name) # Step: Check ECS Service if serviceMode: h1("Step: Check ECS Service") response = ecs.describe_service(cluster=args.cluster_name, service=args.service_name) original_running_count = ( response.get('services')[0]).get('runningCount')
# Arguments parsing parser = argparse.ArgumentParser(description='Deploy Service on ECS') parser.add_argument('--key', dest='key', required=True) parser.add_argument('--secret', dest='secret', required=True) parser.add_argument('--region', dest='region', default='us-east-1') parser.add_argument('--cluster-name', dest='cluster_name', required=True) parser.add_argument('--service-name', dest='service_name', required=True) parser.add_argument('--task-definition-file', dest='task_definition_file', required=True) parser.add_argument('--minimum-running-tasks', type=int, dest='minimum_running_tasks', default=1, required=True) args = parser.parse_args() try: # Step 1: Configuring AWS h1("Step 1: Configuring AWS") ecs = ECSService(access_key=args.key, secret_key=args.secret, region=args.region) success("Configuring AWS succeeded") # Step 2: Check ECS cluster h1("Step 2: Check ECS cluster") ecs.describe_cluster(cluster=args.cluster_name) success("Checking cluster '%s' succeeded" % args.cluster_name) # Step 3: Check ECS Service h1("Step 3: Check ECS Service") response = ecs.describe_service(cluster=args.cluster_name, service=args.service_name) original_running_count = (response.get('services')[0]).get('runningCount') success("Checking service '%s' succeeded (%d tasks running)" % (args.service_name, original_running_count)) # Step 4: Register New Task Definition h1("Step 4: Register New Task Definition")
def __init__(self, key, secret, region): super().__init__() self.ecs_service = ECSService(access_key=key, secret_key=secret, region=region)
class AwsProcess(Thread): def __init__(self, key, secret, region): super().__init__() self.ecs_service = ECSService(access_key=key, secret_key=secret, region=region) def run(self): while True: try: service, mode = task_queue.get_nowait() except Empty: time.sleep(1) continue try: self.process(service, mode) except: service.status = ProcessStatus.error error("Unexpected error. service: %s.\n%s" % (service.service_name, traceback.format_exc())) finally: task_queue.task_done() def process(self, service, mode): if service.status == ProcessStatus.error: error("service '%s' previous process error. skipping." % service.service_name) return if mode == ProcessMode.registerTask: response = self.ecs_service.register_task_definition(task_definition=service.task_definition) service.task_definition_arn = response.get('taskDefinition').get('taskDefinitionArn') success("Registering task definition '%s' succeeded (arn: '%s')" % (service.task_name, service.task_definition_arn)) # for register task rate limit time.sleep(3) elif mode == ProcessMode.checkService: try: response = self.ecs_service.describe_service(service.task_environment.cluster_name, service.service_name) except ServiceNotFoundException: error("Service '%s' not Found." % (service.service_name)) return if response['services'][0]['status'] == 'INACTIVE': error("Service '%s' status is INACTIVE." % (service.service_name)) return service.original_task_definition = (response.get('services')[0]).get('taskDefinition') service.original_running_count = (response.get('services')[0]).get('runningCount') service.original_desired_count = (response.get('services')[0]).get('desiredCount') service.desired_count = service.original_desired_count service.service_exists = True success("Checking service '%s' succeeded (%d tasks running)" % (service.service_name, service.original_running_count)) elif mode == ProcessMode.createService: response = self.ecs_service.create_service(cluster=service.task_environment.cluster_name, service=service.service_name, taskDefinition=service.task_definition_arn, desiredCount=service.task_environment.desired_count, maximumPercent=service.task_environment.maximum_percent, minimumHealthyPercent=service.task_environment.minimum_healthy_percent) service.original_running_count = (response.get('services')[0]).get('runningCount') service.original_desired_count = (response.get('services')[0]).get('desiredCount') service.desired_count = service.original_desired_count success("Create service '%s' succeeded (%d tasks running)" % (service.service_name, service.original_running_count)) elif mode == ProcessMode.updateService: response = self.ecs_service.update_service(cluster=service.task_environment.cluster_name, service=service.service_name, taskDefinition=service.task_definition_arn, maximumPercent=service.task_environment.maximum_percent, minimumHealthyPercent=service.task_environment.minimum_healthy_percent, desiredCount=service.task_environment.desired_count) service.running_count = response.get('services')[0].get('runningCount') service.desired_count = response.get('services')[0].get('desiredCount') success("Update service '%s' with task definition '%s' succeeded" % (service.service_name, service.task_definition_arn)) elif mode == ProcessMode.waitForStable: retryCount = 0 while True: try: response = self.ecs_service.wait_for_stable(cluster=service.task_environment.cluster_name, service=service.service_name) except WaiterError: if retryCount > 2: break retryCount = retryCount + 1 continue break service.running_count = response.get('services')[0].get('runningCount') service.desired_count = response.get('services')[0].get('desiredCount') self.ecs_service.deregister_task_definition(service.original_task_definition) success("service '%s' (%d tasks) update completed" % (service.service_name, service.running_count))
class ServiceManager(object): def __init__(self, args): self.service_list = [] task_definition_config_json = render.load_json(args.task_definition_config_json) files = os.listdir(args.task_definition_template_dir) for file in files: try: task_definitions = render.render_definition(args.task_definition_template_dir, file, task_definition_config_json, args.task_definition_config_env) self.service_list.extend(self.import_service_from_task_definitions(task_definitions)) except: error("Template error. file: %s.\n%s" % (file, traceback.format_exc())) sys.exit(1) if args.deploy_service_group: self.deploy_service_list = list(filter(lambda service:service.task_environment.service_group == args.deploy_service_group, self.service_list)) else: self.deploy_service_list = self.service_list if len(self.deploy_service_list) == 0: error("Deployment target service is None.") sys.exit(1) self.ecs_service = ECSService(access_key=args.key, secret_key=args.secret, region=args.region) self.is_service_zero_keep = args.service_zero_keep self.environment = task_definition_config_json['environment'] self.template_group = args.template_group self.cluster_list = [] for service in self.service_list: if service.task_environment.cluster_name not in self.cluster_list: self.cluster_list.append(service.task_environment.cluster_name) self.error = False def delete_unused_services(self, is_delete_unused_service): h1("Step: Delete Unused Service") if not is_delete_unused_service: info("Do not delete unused service") return cluster_services = {} for cluster_name in self.cluster_list: running_service_arn_list = self.ecs_service.list_services(cluster_name) response = self.ecs_service.describe_services(cluster_name, running_service_arn_list) failures = response.get('failures') # リストからサービス詳細が取れなければエラーにしてしまう if len(failures) > 0: for failure in failures: error("list service failer. service: '%s', reason: '%s'" % (failure.get('arn'), failure.get('reason'))) sys.exit(1) cluster_services[cluster_name] = response['services'] task_definition_names = [] task_dict = {} for cluster_name, d in cluster_services.items(): for service_description in d: service_name = service_description['serviceName'] task_definition_name = service_description['taskDefinition'] response = self.ecs_service.describe_task_definition(task_definition_name) response_task_environment = response['taskDefinition']['containerDefinitions'][0]['environment'] # 環境変数なし if len(response_task_environment) <= 0: error("Service '%s' is environment value not found" % (service_name)) self.error = True continue try: task_environment = TaskEnvironment(response_task_environment) # 環境変数の値が足りない except EnvironmentValueNotFoundException: error("Service '%s' is lack of environment value" % (service_name)) self.error = True continue # 同一環境のものだけ if task_environment.environment != self.environment: continue # 同一テンプレートグループだけ if self.template_group: if not task_environment.template_group: error("Service '%s' is not set TEMPLATE_GROUP" % (service_name)) self.error = True continue if task_environment.template_group != self.template_group: continue ident_service_list = [ service for service in self.service_list if service.service_name == service_name and service.task_environment.cluster_name == cluster_name ] if len(ident_service_list) <= 0: success("Delete service '%s' for service template deleted" % (service_name)) self.ecs_service.delete_service(cluster_name, service_name) def import_service_from_task_definitions(self, task_definitions): service_list = [] for task_definition in task_definitions: service = Service(task_definition) service_list.append(service) return service_list def check_ecs_cluster(self): h1("Step: Check ECS cluster") for cluster_name in self.cluster_list: self.ecs_service.describe_cluster(cluster=cluster_name) success("Checking cluster '%s' succeeded" % cluster_name) def register_new_task_definition(self): h1("Step: Register New Task Definition") for service in self.deploy_service_list: task_queue.put([service, ProcessMode.registerTask]) task_queue.join() def check_service(self): h1("Step: Check ECS Service") for service in self.deploy_service_list: task_queue.put([service, ProcessMode.checkService]) task_queue.join() def create_service(self): # Step: Create ECS Service if necessary not_exists_service_list = list(filter(lambda service:service.service_exists == False, self.deploy_service_list)) if len(not_exists_service_list) > 0: h1("Step: Create ECS Service") for service in not_exists_service_list: task_queue.put([service, ProcessMode.createService]) task_queue.join() def update_service(self): h1("Step: Update ECS Service") for service in self.deploy_service_list: if not service.service_exists: continue if self.is_service_zero_keep and service.original_desired_count == 0: # サービスのタスク数が0だったらそれを維持する info("Service '%s' is zero task service. skipping." % service.service_name) else: task_queue.put([service, ProcessMode.updateService]) task_queue.join() def wait_for_stable(self): h1("Step: Wait for Service Status 'Stable'") for service in self.deploy_service_list: if not service.service_exists: continue else: task_queue.put([service, ProcessMode.waitForStable]) task_queue.join() def result_check(self): error_service_list = list(filter(lambda service:service.status == ProcessStatus.error, self.deploy_service_list)) # サービスでエラーが一個でもあれば失敗としておく if len(error_service_list) > 0: sys.exit(1) if self.error: sys.exit(1)
parser.add_argument('--task-definition-file', dest='task_definition_file', required=True) parser.add_argument('--service-name', dest='service_name', required=False) parser.add_argument('--minimum-running-tasks', type=int, dest='minimum_running_tasks', default=1, required=False) parser.add_argument('--launch-type', dest='launch_type', required=False) parser.add_argument('--execution-role-arn', dest='execution_role_arn', required=False) parser.add_argument('--cpu', dest='cpu', required=False) parser.add_argument('--memory', dest='memory', required=False) args = parser.parse_args() try: serviceMode = args.service_name is not None # Step: Configuring AWS h1("Step: Configuring AWS") ecs = ECSService(access_key=args.key, secret_key=args.secret, region=args.region) success("Configuring AWS succeeded") # Step: Check ECS cluster h1("Step: Check ECS cluster") ecs.describe_cluster(cluster=args.cluster_name) success("Checking cluster '%s' succeeded" % args.cluster_name) # Step: Check ECS Service if serviceMode: h1("Step: Check ECS Service") response = ecs.describe_service(cluster=args.cluster_name, service=args.service_name) original_running_count = (response.get('services')[0]).get('runningCount') success("Checking service '%s' succeeded (%d tasks running)" % (args.service_name, original_running_count)) # Step: Register New Task Definition