def get_or_create_eb_application(): """ https://docs.aws.amazon.com/elasticbeanstalk/latest/api/API_CreateApplication.html """ eb_client = create_eb_client() applications = eb_client.describe_applications().get('Applications', None) for app in applications: app_name = app.get('ApplicationName', None) if app_name and BEIWE_APPLICATION_NAME.lower() in app_name.lower(): log.info('Using Elastic Beanstalk application named "%s."' % app_name) return BEIWE_APPLICATION_NAME # raise Exception("no beiwe applications found") _ = eb_client.create_application( ApplicationName=BEIWE_APPLICATION_NAME, Description='Your Beiwe Application', ResourceLifecycleConfig={ 'ServiceRole': get_or_create_automation_policy()['Arn'], # The ARN of an IAM service role that Elastic Beanstalk has permission to assume 'VersionLifecycleConfig': { 'MaxCountRule': { 'Enabled': False, 'MaxCount': 1000, # should be ignored 'DeleteSourceFromS3': True }, 'MaxAgeRule': { 'Enabled': False, 'MaxAgeInDays': 1000, # should be ignored 'DeleteSourceFromS3': True } } }) return BEIWE_APPLICATION_NAME
def get_python27_platform_arn(): """ gets the most recent platform arm for a python 2.7 elastic beanstalk cluster. Warning! The query below returns different values in different AWS regions. We've tested this in us-east-1, us-east-2, us-west-1, and us-west-2 on November 1, 2017 and confirmed that those 4 regions worked; however, this call may not work for other AWS regions, and it may break if Amazon changes the return values in the future. """ eb_client = create_eb_client() platforms = [] botoFilters = [{'Operator': 'contains', 'Type': 'PlatformName', 'Values': ['Python']}] # Note: regardless of the MaxRecords value, we're only seeing boto3 return 100 records max for platform in eb_client.list_platform_versions(MaxRecords=1000, Filters=botoFilters)['PlatformSummaryList']: if (platform.get('PlatformCategory', None) == 'Python' and "Python 2.7" in platform.get('PlatformArn', []) and "64bit Amazon Linux" in platform.get('PlatformArn', []) ): platforms.append(platform['PlatformArn']) platforms.sort() if len(platforms) == 0: raise PythonPlatformDiscoveryError("could not find python 2.7 platform") if len(platforms) > 1: log.error("\n***********************************************************\n" "Warning: encountered multiple Python 2.7 Elastic Beanstalk environment platforms.\n" "Beiwe did its best to automatically determine which environment to use.\n" "After deployment finishes, determine whether there is a platform upgrade you can\n" "apply for this cluster.\n" "***********************************************************") return platforms[-1] if len(platforms) == 1: return platforms[0]
def get_python36_platform_arn(): """ Gets the most recent platform arn for a python 3.6 elastic beanstalk cluster, is region specific..""" eb_client = create_eb_client() platforms = [] botoFilters = [{'Operator': 'contains', 'Type': 'PlatformName', 'Values': ['Python']}] # Note: regardless of the MaxRecords value, we're only seeing boto3 return 100 records max for platform in eb_client.list_platform_versions(MaxRecords=1000, Filters=botoFilters)['PlatformSummaryList']: if (platform.get( 'PlatformCategory', None) == 'Python' and "Python 3.6" in platform.get('PlatformArn', []) and "64bit Amazon Linux" in platform.get('PlatformArn', []) ): platforms.append(platform['PlatformArn']) # platform arns are not necessarily human-alphanumerically, but a best effort here is fine. # looks like this: # ['arn:aws:elasticbeanstalk:us-east-1::platform/Python 3.6 running on 64bit'Amazon Linux/2.9.2', # 'arn:aws:elasticbeanstalk:us-east-1::platform/Python 3.6 running on 64bit Amazon Linux/2.9.3'] platforms.sort() if len(platforms) == 0: raise PythonPlatformDiscoveryError("could not find python 3.6 platform") if len(platforms) > 1: log.error("\n***********************************************************\n" "Warning: encountered multiple Python 3.6 Elastic Beanstalk environment platforms.\n" "Beiwe did its best to automatically determine which environment to use.\n" "After deployment finishes, determine whether there is a platform upgrade you can\n" "apply for this cluster.\n" "***********************************************************") return platforms[-1] if len(platforms) == 1: return platforms[0]
def fix_deploy(eb_environment_name): # { # 'ResourceName': 'string', # 'Namespace': 'string', # 'OptionName': 'string', # 'Value': 'string' # }, eb_client = create_eb_client() return eb_client.update_environment( # ApplicationName='string', # EnvironmentId='string', EnvironmentName=eb_environment_name, # GroupName='string', # Description='string', # Tier={ # 'Name': 'string', # 'Type': 'string', # 'Version': 'string' # # }, # VersionLabel='string', # TemplateName='string', # SolutionStackName='string', # PlatformArn='string', OptionSettings=[ { 'Namespace': 'aws:elasticbeanstalk:command', 'OptionName': 'IgnoreHealthCheck', 'Value': 'true' }, ], # OptionsToRemove=[ # { # 'ResourceName': 'string', # 'Namespace': 'string', # 'OptionName': 'string' # }, # ] )
def create_eb_environment(eb_environment_name, without_db=False): # Don't actually use the without_db flag in production, it is for debugging app = get_or_create_eb_application() # if not without_db: # try: # _ = get_db_info(eb_environment_name) # except DBInstanceNotFound: # log.error("could not find a database named '%s,' you must create a database first." # % construct_db_name(eb_environment_name)) # EXIT() option_settings = construct_eb_environment_variables(eb_environment_name) log.info( "creating a new Elastic Beanstalk environment named %s... this will take a while." % eb_environment_name) eb_client = create_eb_client() env = eb_client.create_environment( ApplicationName=BEIWE_APPLICATION_NAME, EnvironmentName=eb_environment_name, Description='elastic beanstalk beiwe cluster', PlatformArn=get_python36_platform_arn(), OptionSettings=option_settings, # VersionLabel='string', # TODO: this will probably be required later? # a different form of configuration management # OptionsToRemove=[ # {'ResourceName': 'string', # 'Namespace': 'string', # 'OptionName': 'string'}] # Tags=[{'Key': 'string', # 'Value': 'string'}], # CNAMEPrefix='string', # not required # Tier={'Name': 'string', # 'Type': 'string', # 'Version': 'string'}, # GroupName='string', # for use in other methods of eb configuration # TemplateName='string', # nope # SolutionStackName='string', # more about templates ) env_id = env['EnvironmentId'] good_eb_environment_states = ["Launching", "Updating"] bad_eb_environment_states = ["Terminating", "Terminated"] while True: envs = retry(eb_client.describe_environments, EnvironmentIds=[env_id])['Environments'] log.info( '%s: Elastic Beanstalk status is "%s", waiting until status is "Ready"' % (current_time_string(), env['Status'])) if len(envs) != 1: raise Exception( "describe_environments is broken, %s environments returned" % len(envs)) env = envs[0] if env['Status'] in bad_eb_environment_states: msg = "environment deployment failed:\n%s" % format(env) log.error( msg ) # python logging is weird and this fails to print if python exits too quickly. raise EnvironmentDeploymentFailure(msg) if env['Status'] in good_eb_environment_states: sleep(5) continue if env['Status'] == "Ready": log.info("environment %s, is ready to have Beiwe deployed to it." % eb_environment_name) break encrypt_eb_s3_bucket() allow_eb_environment_database_access(eb_environment_name) allow_443_traffic_to_load_balancer(eb_environment_name) return env
def get_environment(eb_environment_name): eb_client = create_eb_client() return eb_client.describe_configuration_settings( ApplicationName="beiwe-application", EnvironmentName=eb_environment_name)['ConfigurationSettings'][0]
def get_environments_list(): environments = create_eb_client().describe_environments()['Environments'] return [environment['EnvironmentName'] for environment in environments]