def purge_launch_configuration(cloud_connection, app, retention): """ Removes the old launch configurations except the `retention`th latest :param cloud_connection: object: :param app: object: :param retention: int: :return: bool: """ conn_as = cloud_connection.get_connection(app['region'], ["autoscaling"], boto_version='boto3') paginator = conn_as.get_paginator('describe_launch_configurations') lcs = [] for page in paginator.paginate(): lcs = lcs + page['LaunchConfigurations'] blue_green, app_color = get_blue_green_from_app(app) launchconfig_prefix = _format_launchconfig_name(app, app_color, only_prefix=True) lcs = [ lc for lc in lcs if lc['LaunchConfigurationName'].startswith(launchconfig_prefix) ] lcs = sorted(lcs, key=lambda lc: lc['CreatedTime'], reverse=True)[retention:] for lc in lcs: try: conn_as.delete_launch_configuration( LaunchConfigurationName=lc['LaunchConfigurationName']) except ClientError as e: if e.response.get('Error', {}).get('Code') != 'ResourceInUse': raise return True
def create_launch_config(cloud_connection, app, userdata, ami_id): blue_green, app_color = get_blue_green_from_app(app) launchconfig_name = _format_launchconfig_name(app, app_color) conn_as = cloud_connection.get_connection(app['region'], ["ec2", "autoscale"]) instance_monitoring = app.get('instance_monitoring', False) launch_config = cloud_connection.launch_service( ["ec2", "autoscale", "LaunchConfiguration"], connection=conn_as, name=launchconfig_name, image_id=ami_id, key_name=app['environment_infos']['key_name'], security_groups=app['environment_infos']['security_groups'], user_data=userdata, instance_type=app['instance_type'], kernel_id=None, ramdisk_id=None, block_device_mappings=get_block_devices_mapping(cloud_connection, app), instance_monitoring=instance_monitoring, spot_price=None, instance_profile_name=app['environment_infos']['instance_profile'], ebs_optimized=False, associate_public_ip_address=app['environment_infos'].get( 'public_ip_address', True), volume_type=None, delete_on_termination=True, iops=None, classic_link_vpc_id=None, classic_link_vpc_security_groups=None) conn_as.create_launch_configuration(launch_config) return launch_config
def is_available(app_context=None): ghost_has_blue_green = ghost_has_blue_green_enabled() if not ghost_has_blue_green: return False if not app_context: return True app_blue_green, app_color = get_blue_green_from_app(app_context) return app_blue_green is not None and app_color is not None
def post_update_app(updates, original): try: # Enable green app only if not already enabled blue_green, color = get_blue_green_from_app(original) if ghost_api_bluegreen_is_enabled(updates) and not color: # Maybe we need to have the "merged" app after update here instead of "original" one ? if not ghost_api_enable_green_app(get_apps_db(), original, request.authorization.username): abort(422) except Exception as e: print "Exception occured" print e abort(500)
def __init__(self, worker): self._app = worker.app self._job = worker.job self._config = worker._config self._worker = worker self._log_file = worker.log_file self._connection_data = get_aws_connection_data( self._app.get('assumed_account_id', ''), self._app.get('assumed_role_name', ''), self._app.get('assumed_region_name', '')) self._cloud_connection = cloud_connections.get( self._app.get('provider', DEFAULT_PROVIDER))(self._config, **self._connection_data) blue_green, self._color = get_blue_green_from_app(self._app)
def __init__(self, app, job, db, log_file, config): self._app = app self._job = job self._db = db self._log_file = log_file self._config = config blue_green, self._color = get_blue_green_from_app(self._app) self._ami_name = AMI_FMT.format(env=self._app['env'], region=self._app['region'], role=self._app['role'], name=self._app['name'], date=time.strftime("%Y%m%d-%H%M%S"), color='.%s' % self._color if self._color else '') self.unique = str(job['_id']) self.packer_directory_path = os.path.join(PACKER_JSON_PATH, self.unique) if not os.path.exists(self.packer_directory_path): os.makedirs(self.packer_directory_path)
def ghost_api_check_green_app_exists(apps_db, app): """ Check if the Alter Ego application exists ie: the blue one or the green one (depending of the current app color) """ name = app.get('name') role = app.get('role') env = app.get('env') blue_green, color = get_blue_green_from_app(app) if not color: color = 'blue' # handle default one green_app = apps_db.find_one({ '$and': [{ 'name': name }, { 'role': role }, { 'env': env }, { 'blue_green.color': OPPOSITE_COLOR[color] }] }) return green_app
def pre_update_app(updates, original): """ eve pre-update event hook to reset modified modules' 'initialized' field. Uninitialized modules stay so, modified or not: >>> from copy import deepcopy >>> base_original = {'_id': 1111, 'env': 'prod', 'name': 'app1', 'role': 'webfront', 'modules': [ ... {'name': 'mod1', 'git_repo': '[email protected]/test/mod1', 'path': '/tmp/ok'}, ... {'name': 'mod2', 'git_repo': '[email protected]/test/mod2', 'path': '/tmp/ok'}], ... 'environment_infos': {'instance_tags':[]}} >>> original = deepcopy(base_original) >>> updates = deepcopy(base_original) >>> pre_update_app(updates, original) >>> updates['modules'][0]['initialized'] False >>> updates['modules'][1]['initialized'] False Initialized modules stay so if not modified: >>> original['modules'][0]['initialized'] = True >>> original['modules'][1]['initialized'] = True >>> updates = deepcopy(base_original) >>> pre_update_app(updates, original) >>> updates['modules'][0]['initialized'] True >>> updates['modules'][1]['initialized'] True Modified modules get their 'initialized' field reset to False: >>> updates = deepcopy(base_original) >>> updates['modules'][1]['git_repo'] = '[email protected]/test/mod2-modified' >>> pre_update_app(updates, original) >>> updates['modules'][0]['initialized'] True >>> updates['modules'][1]['initialized'] False Modified modules get their 'initialized' field reset to False also in case of new fields: >>> updates = deepcopy(base_original) >>> updates['modules'][1]['uid'] = '101' >>> updates['modules'][1]['gid'] = '102' >>> pre_update_app(updates, original) >>> updates['modules'][0]['initialized'] True >>> updates['modules'][1]['initialized'] False New modules get their 'initialized' field set to False by default: >>> updates = deepcopy(base_original) >>> updates['modules'].append({'name': 'mod3', 'git_repo': '[email protected]/test/mod3', 'path': '/tmp/ok'}) >>> pre_update_app(updates, original) >>> updates['modules'][0]['initialized'] True >>> updates['modules'][1]['initialized'] True >>> updates['modules'][2]['initialized'] False """ try: ghost_api_app_data_input_validator(updates) except GhostAPIInputError as error: abort(422, description=error.message) # Selectively reset each module's 'initialized' property if any of its other properties have changed updates, modules_edited = initialize_app_modules(updates, original) user = request.authorization.username if request and request.authorization else 'Nobody' updates = check_and_set_app_fields_state(user, updates, original, modules_edited) if 'environment_infos' in updates and 'instance_tags' in updates[ 'environment_infos']: updates['environment_infos'][ 'instance_tags'] = normalize_application_tags(original, updates) # Blue/green disabled ? try: blue_green_section, color = get_blue_green_from_app(updates) if (blue_green_section and 'enable_blue_green' in blue_green_section and isinstance(blue_green_section['enable_blue_green'], bool) and not blue_green_section['enable_blue_green']): if not ghost_api_clean_bluegreen_app(get_apps_db(), original): abort(422) if not ghost_api_delete_alter_ego_app(get_apps_db(), original): abort(422) del updates['blue_green'] except Exception as e: print e abort(500)