def _zip_logs_location(logs_location): fileoperations.zip_up_folder(logs_location, logs_location + '.zip') fileoperations.delete_directory(logs_location) logs_location += '.zip' fileoperations.set_user_only_permissions(logs_location) io.echo(strings['logs.location'].replace('{location}', logs_location))
def complete_region(self, commands): # we only care about top command cmd = commands[-1] if cmd == '-r' or cmd == '--region': io.echo(*[r.name for r in region.get_all_regions()]) return True return False
def delete_platform_version(platform_version, force=False): arn = _version_to_arn(platform_version) if not force: io.echo(prompts['platformdelete.confirm'].replace('{platform-arn}', arn)) io.validate_action(prompts['platformdelete.validate'], arn) environments = [] try: environments = [env for env in elasticbeanstalk.get_environments() if env.platform.version == arn] except NotFoundError: pass if len(environments) > 0: _, platform_name, platform_version = PlatformVersion.arn_to_platform(arn) raise ValidationError(strings['platformdeletevalidation.error'].format( platform_name, platform_version, '\n '.join([env.name for env in environments]) )) response = elasticbeanstalk.delete_platform(arn) request_id = response['ResponseMetadata']['RequestId'] timeout = 10 commonops.wait_for_success_events(request_id, timeout_in_minutes=timeout, platform_arn=arn)
def delete_app_version_label(app_name, version_label): if version_label: # check if version_label exists under app_name app_versions = elasticbeanstalk.get_application_versions(app_name)['ApplicationVersions'] # if the given version label does not exist at all! if not any(version_label == app_version['VersionLabel'] for app_version in app_versions): raise ValidationError(strings['appversion.delete.notfound'].format(app_name, version_label)) envs = elasticbeanstalk.get_app_environments(app_name) versions_in_use = [(e.version_label, e.name) for e in envs] # find all the environments that are using the app version used_envs = [version[1] for version in versions_in_use if version[0] == version_label] if used_envs: raise ValidationError(strings['appversion.delete.deployed'].format(version_label, ','.join(used_envs))) try: io.validate_action(prompts['appversion.delete.validate'].format(version_label), "y") elasticbeanstalk.delete_application_version(app_name, version_label) io.echo('Application Version deleted successfully.') delete_successful = True except ValidationError: io.echo('Application Version will not be deleted.') delete_successful = False return delete_successful else: raise NotFoundError(strings['appversion.delete.none'])
def do_command(self): version = self.app.pargs.version stream = self.app.pargs.stream if version is None: platform_name = fileoperations.get_platform_name() version = fileoperations.get_platform_version() else: platform_name = fileoperations.get_platform_name() if VALID_PLATFORM_VERSION_FORMAT.match(version): pass elif PlatformVersion.is_valid_arn(version): _, platform_name, version = PlatformVersion.arn_to_platform(version) elif VALID_PLATFORM_SHORT_FORMAT.match(version): match = VALID_PLATFORM_SHORT_FORMAT.match(version) platform_name, version = match.group(1, 2) else: raise InvalidPlatformVersionError(strings['exit.invalidversion']) io.echo('Retrieving logs...') if stream: try: logsops.stream_platform_logs( platform_name, version, log_name="%s/%s" % (platform_name, version), # Packer is our only builder type at this point formatter=platformops.PackerStreamFormatter()) except NotFoundError: raise NotFoundError('Unable to find logs in CloudWatch.') else: # print with paginator paginate_cloudwatch_logs(platform_name, version)
def update_environment_with_config_data(env_name, data, nohang, timeout=None): if fileoperations.env_yaml_exists(): io.echo(strings['config.envyamlexists']) commonops.update_environment(env_name, None, nohang, timeout=timeout, template_body=data)
def do_command(self): force = self.app.pargs.force delete_application_and_resources = self.app.pargs.all ignore_links = self.app.pargs.ignore_links timeout = self.app.pargs.timeout nohang = self.app.pargs.nohang if delete_application_and_resources: app_name = self.get_app_name() cleanup = not self.app.pargs.region terminateops.delete_app( app_name, force, nohang=nohang, cleanup=cleanup, timeout=timeout ) else: env_name = self.get_env_name() if not force: io.echo(prompts['terminate.confirm'].format(env_name=env_name)) io.validate_action(prompts['terminate.validate'], env_name) terminateops.terminate( env_name, force_terminate=ignore_links, nohang=nohang, timeout=timeout )
def prompt_customer_for_custom_platform_version(version_to_arn_mappings): custom_platform_versions_to_display = sorted(version_to_arn_mappings.keys()) io.echo() io.echo(prompts['sstack.version']) chosen_custom_platform_version = utils.prompt_for_item_in_list(custom_platform_versions_to_display) return version_to_arn_mappings[chosen_custom_platform_version]
def interactive_update_lifcycle_policy(app_name): # Get current application settings api_model = elasticbeanstalk.describe_application(app_name) # Convert into yaml format from raw API lifecycle_config = LifecycleConfiguration(api_model) usr_model = lifecycle_config.convert_api_to_usr_model() # Save yaml file into temp file file_location = fileoperations.save_app_file(usr_model) fileoperations.open_file_for_editing(file_location) # Update and delete file try: usr_model = fileoperations.get_application_from_file(app_name) config_changes = lifecycle_config.collect_changes(usr_model) fileoperations.delete_app_file(app_name) except InvalidSyntaxError: io.log_error(strings['lifecycle.invalidsyntax']) fileoperations.delete_app_file(app_name) return if not config_changes: # no changes made, exit io.log_warning(strings['lifecycle.updatenochanges']) return elasticbeanstalk.update_application_resource_lifecycle(app_name, config_changes) io.echo(strings['lifecycle.success'])
def messages_handler(messages): messages = '{linesep}{linesep}============= {log_stream} - {log_group} =============={linesep}{linesep}{messages}'.format( log_stream=stream_name, log_group=log_group_name, linesep=os.linesep, messages=os.linesep.join(messages) ) io.echo(messages)
def _echo_link_to_cloudwatch_console(env_name): region = commonops.get_default_region() if region in ['cn-north-1', 'cn-northwest-1']: cw_link_regionalized = strings['cloudwatch-logs.bjslink'] else: cw_link_regionalized = strings['cloudwatch-logs.link'] io.echo(cw_link_regionalized.replace('{region}', region).replace('{env_name}', env_name))
def recursive_print_api_dict(config, spaced=2): for entry in config: entry_value = config[u'{0}'.format(entry)] if isinstance(entry_value, dict): io.echo('{0}{1}:'.format(SPACER * spaced, entry)) recursive_print_api_dict(entry_value, spaced + 1) else: io.echo('{0}{1}: {2}'.format(SPACER * spaced, entry, entry_value))
def set_workspace_to_latest(): platform_name = fileoperations.get_platform_name() version = _get_latest_version(platform_name, owner=Constants.OWNED_BY_SELF) fileoperations.update_platform_version(version) if version is not None: io.echo(strings['platformset.version']) get_version_status(version)
def download_config_from_s3(app_name, cfg_name): bucket = elasticbeanstalk.get_storage_location() body = s3.get_object(bucket, _get_s3_keyname_for_template(app_name, cfg_name)) location = write_to_local_config(cfg_name, body) fileoperations.set_user_only_permissions(location) io.echo() io.echo('Configuration saved at: ' + location)
def complete_command(self, commands): """ Implement this method for autocompletion to work You do not have to worry about the --flags, only positional arguments :param commands: A list of commands on the command line so fat """ # Print out all possible options. The completer function is smart ## enough to filter out the ones that dont match io.echo('option1') io.echo('option2')
def _handle_bundle_logs(instance_id_list, do_zip): logs_folder_name = _timestamped_directory_name() logs_location = fileoperations.get_logs_location(logs_folder_name) _download_logs_for_all_instances(instance_id_list, logs_location) fileoperations.set_user_only_permissions(logs_location) if do_zip: _handle_log_zipping(logs_location) else: io.echo(strings['logs.location'].replace('{location}', logs_location)) _attempt_update_symlink_to_latest_logs_retrieved(logs_location)
def _handle_log_zipping(logs_location): logs_zip = logs_location + '.zip' fileoperations.zip_up_folder(logs_location, logs_zip) fileoperations.delete_directory(logs_location) fileoperations.set_user_only_permissions(logs_zip) io.echo( strings['logs.location'].replace( '{location}', logs_zip ) )
def snapshot_file_view(self): data_repr = self.data current_time = datetime.now().strftime("%y%m%d-%H%M%S") filename = 'health-snapshot-' + current_time + '.json' filelocation = fileoperations.get_eb_file_full_location(filename) fileoperations.write_json_dict(data_repr, filelocation) t = term.get_terminal() with t.location(y=self.empty_row, x=2): io.echo(io.bold('Snapshot file saved at: .elasticbeanstalk/' + filename), end=' ') sys.stdout.flush() time.sleep(4)
def complete_command(self, commands): workspace_type = fileoperations.get_workspace_type(Constants.WorkSpaceTypes.APPLICATION) # We only care about regions if len(commands) == 1: # They only have the main command so far # lets complete for next level command if Constants.WorkSpaceTypes.APPLICATION == workspace_type: io.echo(*['list', 'use', 'status']) elif Constants.WorkSpaceTypes.PLATFORM == workspace_type: io.echo(*['create', 'delete', 'events', 'init', 'list', 'status', 'use']) elif len(commands) > 1: pass
def get_platform_name_and_version_interactive(): platforms = get_platforms(owner=Constants.OWNED_BY_SELF, platform_version="latest") platform_list = list(platforms) file_name = fileoperations.get_current_directory_name() new_platform = False version = None if len(platform_list) > 0: io.echo() io.echo('Select a platform to use') new_platform_option = '[ Create new Platform ]' platform_list.append(new_platform_option) try: default_option = platform_list.index(file_name) + 1 except ValueError: default_option = len(platform_list) platform_name = utils.prompt_for_item_in_list(platform_list, default=default_option) if platform_name == new_platform_option: new_platform = True else: version = platforms[platform_name] if len(platform_list) == 0 or new_platform: io.echo() io.echo('Enter Platform Name') unique_name = utils.get_unique_name(file_name, platform_list) platform_name = io.prompt_for_unique_name(unique_name, platform_list) return platform_name, version
def _get_application_name_interactive(): app_list = elasticbeanstalk.get_application_names() file_name = fileoperations.get_current_directory_name() new_app = False if len(app_list) > 0: io.echo() io.echo('Select an application to use') new_app_option = '[ Create new Application ]' app_list.append(new_app_option) try: default_option = app_list.index(file_name) + 1 except ValueError: default_option = len(app_list) app_name = utils.prompt_for_item_in_list(app_list, default=default_option) if app_name == new_app_option: new_app = True if len(app_list) == 0 or new_app: io.echo() io.echo('Enter Application Name') unique_name = utils.get_unique_name(file_name, app_list) app_name = io.prompt_for_unique_name(unique_name, app_list) return app_name
def detect_platform(): """ Method attempts to guess the language name depending on the application source code and asks the customer to verify whether the guess is correct. :return: A string containing the name of the platform if the customer approves, otherwise None """ detected_platform = heuristics.find_language_type() if detected_platform: io.echo() io.echo(prompts['platform.validate'].replace('{platform}', detected_platform)) correct = io.get_boolean_response() if correct: return detected_platform
def set_platform(platform_name, platform_version=None, verify=True): if verify: arn = _name_to_arn(platform_name) _, platform_name, platform_version = PlatformVersion.arn_to_platform(arn) fileoperations.update_platform_name(platform_name) fileoperations.update_platform_version(platform_version) io.echo(strings['platformset.version']) # This could fail if the customer elected to create a new platform try: get_version_status(platform_version) except InvalidPlatformVersionError: io.echo(strings['platformset.newplatform'] % platform_name)
def create_codecommit_branch(source_control, branch_name): current_commit = source_control.get_current_commit() # Creating the branch requires that we setup the remote branch first # to ensure the code commit branch is synced with the local branch if current_commit is None: # TODO: Test on windows for weird empty returns with the staged files staged_files = source_control.get_list_of_staged_files() if not staged_files: source_control.create_initial_commit() else: LOG.debug("Cannot create placeholder commit because there are staged files: {0}".format(staged_files)) io.echo("Could not set create a commit with staged files; cannot setup CodeCommit branch without a commit") return None source_control.setup_new_codecommit_branch(branch_name=branch_name) io.echo("Successfully created branch: {0}".format(branch_name))
def do_command(self): verbose = self.app.pargs.verbose solution_stacks = platformops.get_all_platforms() if verbose: platform_arns = platformops.list_custom_platform_versions() lst = [s.name for s in solution_stacks] lst.extend(platform_arns) else: platform_arns = platformops.list_custom_platform_versions(platform_version='latest') lst = sorted(set([s.pythonify() for s in solution_stacks])) lst.extend([PlatformVersion.get_platform_name(arn) for arn in platform_arns]) if len(lst) > 20: io.echo_with_pager(os.linesep.join(lst)) else: io.echo(*lst, sep=os.linesep)
def do_command(self): """ This method actually does the command """ io.echo('Hello World!') for arg in self.app.pargs.positional_arg: io.echo(arg) if self.app.pargs.foo: io.echo(self.app.pargs.foo) if self.app.pargs.vendetta: io.echo('Vendetta Flag was set') if self.app.pargs.hidden: io.echo('The hidden flag was set')
def get_region(region_argument, interactive, force_non_interactive=False): # Get region from command line arguments region = get_region_from_inputs(region_argument) # Ask for region if (not region) and force_non_interactive: # Choose defaults region_list = regions.get_all_regions() region = region_list[2].name if not region or (interactive and not region_argument): io.echo() io.echo('Select a default region') region_list = regions.get_all_regions() result = utils.prompt_for_item_in_list(region_list, default=3) region = result.name return region
def prompt_for_index_in_list(lst, default=1): lst = list(lst) for x in range(0, len(lst)): io.echo(str(x + 1) + ')', lst[x]) while True: try: choice = int(io.prompt('default is ' + str(default), default=default)) if not (0 < choice <= len(lst)): raise ValueError # Also thrown by non int numbers else: break except ValueError: io.echo('Sorry, that is not a valid choice. ' 'Please choose a number between 1 and ' + str(len(lst)) + '.') return choice - 1
def should_download_sample_app(): """ Method determines whether the present directory is empty. If yes, it allows the user to choose to download the sample application that the environment will be launched with. :return: User's choice of whether the sample application should be downloaded """ user_input = None if heuristics.directory_is_empty(): io.echo(strings['create.sample_application_download_option']) user_input = download_sample_app_user_choice() while user_input not in ['y', 'n', 'Y', 'N']: io.echo(strings['create.download_sample_app_choice_error'].format(choice=user_input)) user_input = download_sample_app_user_choice() return True if user_input in ['y', 'Y'] else False
def create_env(env_request, interactive=True): # If a template is being used, we want to try using just the template if env_request.template_name: platform = env_request.platform env_request.platform = None else: platform = None while True: try: return elasticbeanstalk.create_environment(env_request) except InvalidParameterValueError as e: if e.message == responses['app.notexists'].replace( '{app-name}', '\'' + env_request.app_name + '\''): # App doesnt exist, must be a new region. ## Lets create the app in the region commonops.create_app(env_request.app_name) elif e.message == responses['create.noplatform']: if platform: env_request.platform = platform else: raise elif interactive: LOG.debug('creating env returned error: ' + e.message) if re.match(responses['env.cnamenotavailable'], e.message): io.echo(prompts['cname.unavailable']) cname = io.prompt_for_cname() elif re.match(responses['env.nameexists'], e.message): io.echo(strings['env.exists']) current_environments = elasticbeanstalk.get_all_environment_names() unique_name = utils.get_unique_name(env_request.env_name, current_environments) env_request.env_name = io.prompt_for_environment_name( default_name=unique_name) elif e.message == responses['app.notexists'].replace( '{app-name}', '\'' + env_request.app_name + '\''): # App doesnt exist, must be a new region. ## Lets create the app in the region commonops.create_app(env_request.app_name) else: raise else: raise
def get_repository_interactive(): source_control = SourceControl.get_source_control() # Give list of code commit repositories to use new_repo = False repo_list = codecommit.list_repositories()["repositories"] current_repository = source_control.get_current_repository() current_repository = current_repository or fileoperations.get_current_directory_name( ) # If there are existing repositories prompt the user to pick one # otherwise set default as the file name if len(repo_list) > 0: repo_list = list(map(lambda r: r["repositoryName"], repo_list)) io.echo() io.echo('Select a repository') new_repo_option = '[ Create new Repository ]' repo_list.append(new_repo_option) try: default_option = repo_list.index(current_repository) + 1 except ValueError: default_option = len(repo_list) repo_name = utils.prompt_for_item_in_list(repo_list, default=default_option) if repo_name == new_repo_option: new_repo = True # Create a new repository if the user specifies or there are no existing repositories if len(repo_list) == 0 or new_repo: io.echo() io.echo('Enter Repository Name') unique_name = utils.get_unique_name(current_repository, repo_list) repo_name = io.prompt_for_unique_name(unique_name, repo_list) # Create the repository if we get here codecommit.create_repository(repo_name, "Created with EB CLI") io.echo("Successfully created repository: {0}".format(repo_name)) return repo_name
def prompt_for_ec2_keyname(env_name=None, message=None, keyname=None): if message is None: message = prompts['ssh.setup'] if env_name: io.validate_action(prompts['terminate.validate'], env_name) else: io.echo(message) ssh = io.get_boolean_response() if not ssh: return None keys = [k['KeyName'] for k in ec2.get_key_pairs()] default_option = len(keys) if keyname: for index, key in enumerate(keys): if key == keyname: # The selection is between 1 and len(keys) default_option = index + 1 if len(keys) < 1: keyname = _generate_and_upload_keypair(keys) else: new_key_option = '[ Create new KeyPair ]' keys.append(new_key_option) io.echo() io.echo(prompts['keypair.prompt']) keyname = utils.prompt_for_item_in_list(keys, default=default_option) if keyname == new_key_option: keyname = _generate_and_upload_keypair(keys) return keyname
def generate_self_signed_cert(cert_name): home = fileoperations.get_home() cert_dir = os.path.join(home, '.ssl') privatekey_filename = cert_name + '-privatekey.pem' privatekey_dir = os.path.join(cert_dir, privatekey_filename) sign_request_filename = cert_name + '-csr.pem' sign_request_dir = os.path.join(cert_dir, sign_request_filename) server_cert_filename = cert_name + '.crt' server_cert_dir = os.path.join(cert_dir, server_cert_filename) if not os.path.isdir(cert_dir): os.mkdir(cert_dir) io.log_warning('Generating a self-signed certificate. ' 'To provide an already created certificate, ' 'use the command options.' '\nSee "eb labs setup-ssl --help" for more info.') if not fileoperations.program_is_installed('openssl'): raise CommandError('This command requires openssl to be ' 'installed on the PATH') if not os.path.isfile(privatekey_dir): utils.exec_cmd_quiet(['openssl', 'genrsa', '-out', privatekey_dir]) if not os.path.isfile(sign_request_dir): io.echo() subprocess.check_call([ 'openssl', 'req', '-new', '-key', privatekey_dir, '-out', sign_request_dir ]) io.echo() if not os.path.isfile(server_cert_dir): utils.exec_cmd_quiet([ 'openssl', 'x509', '-req', '-days', '365', '-in', sign_request_dir, '-signkey', privatekey_dir, '-out', server_cert_dir ]) return privatekey_dir, server_cert_dir
def cleanup_platforms(self): force = self.app.pargs.force all_platforms = self.app.pargs.all_platforms if all_platforms: platform_name = None else: platform_name = fileoperations.get_platform_name() failed_versions = sorted( platform_version_ops.list_custom_platform_versions( platform_name=platform_name, status='Failed', )) if failed_versions: if not force: if not platform_name: io.echo(prompts['cleanupplatform.confirm'].replace( '{platform-name}', 'All Platforms')) for failed_version in failed_versions: io.echo(failed_version) io.validate_action(prompts['cleanupplatform.validate-all'], 'all') else: io.echo(prompts['cleanupplatform.confirm'].replace( '{platform-name}', platform_name)) io.validate_action(prompts['cleanupplatform.validate'], platform_name) for failed_version in failed_versions: platform_version_ops.delete_platform_version(failed_version, force=True)
def scale(app_name, env_name, number, confirm, timeout=None): options = [] env = elasticbeanstalk.describe_configuration_settings( app_name, env_name )['OptionSettings'] namespace = 'aws:elasticbeanstalk:environment' setting = next((n for n in env if n["Namespace"] == namespace), None) value = setting['Value'] if value == 'SingleInstance': if not confirm: io.echo(prompts['scale.switchtoloadbalance']) io.log_warning(prompts['scale.switchtoloadbalancewarn']) switch = io.get_boolean_response() if not switch: return options.append({'Namespace': namespace, 'OptionName': 'EnvironmentType', 'Value': 'LoadBalanced'}) namespace = 'aws:autoscaling:asg' max = 'MaxSize' min = 'MinSize' for name in [max, min]: options.append( { 'Namespace': namespace, 'OptionName': name, 'Value': str(number) } ) request_id = elasticbeanstalk.update_environment(env_name, options) commonops.wait_for_success_events( request_id, timeout_in_minutes=timeout or 5, can_abort=True )
def open_webpage(cnt_viewmodel): """ Open the webpage at container ip and host port we exposed when we ran this container. Raise error if container not running and prompt user to choose host port if multiple host ports exposed under this container. :param cnt_viewmodel: ContainerViewModel: contains view info about container :return: None """ if not cnt_viewmodel.is_running(): raise RuntimeError(strings['local.open.nocontainer']) # Get container id, exposed host port pairs cid_hostports = cnt_viewmodel.get_cid_hostport_pairs() num_exposed_hostports = cnt_viewmodel.num_exposed_hostports() if num_exposed_hostports == 1: _, host_port = cid_hostports[0] elif num_exposed_hostports > 1: io.echo() io.echo('Select a container applcation to open') io.echo() disp = ['Container {}, host port {}'.format(cid, p) for cid, p in cid_hostports] ind = utils.prompt_for_index_in_list(disp) _, host_port = cid_hostports[ind] else: raise RuntimeError(strings['local.open.noexposedport']) url = '{}:{}'.format(cnt_viewmodel.ip, host_port) commonops.open_webpage_in_browser(url)
def _print_codecommit_repositories(): default_branch = gitops.get_default_branch() default_repo = gitops.get_default_repository() if default_repo and default_branch: io.echo("Current CodeCommit settings:") io.echo(" Repository: " + str(default_repo)) io.echo(" Branch: " + str(default_branch))
def restore_environment_num(self, environment_number): """Take in user input as a string, convert it to a decimal, get the environment that the user input matches, and attempt to restore that environment. """ environment_number = int(environment_number) # raises InvalidOperation Exception environments = self.poller.all_environments e_len = len(environments) if environment_number > e_len or environment_number < 1: raise IndexError environment = environments[e_len - environment_number] env_id = environment.get(u'EnvironmentId') should_exit_display = True if env_id: self.flusher(term.get_terminal()) prompt_text = prompts['restore.selectedenv'].format( env_id=env_id, app=utils.encode_to_ascii(environment.get('ApplicationName')), desc=utils.encode_to_ascii(environment.get('Description')), cname=utils.encode_to_ascii(environment.get('CNAME')), version=utils.encode_to_ascii(environment.get('VersionLabel')), platform=utils.encode_to_ascii(environment.get('SolutionStackName')), dat_term=environment.get('DateUpdated')) should_restore = io.get_boolean_response(prompt_text, default=True) if not should_restore: io.echo(responses['restore.norestore']) time.sleep(1) should_exit_display = False return should_exit_display from ebcli.operations import restoreops # restore specified environment self.request_id = restoreops.restore(env_id) return should_exit_display # Exception should never get thrown else: raise Exception
def create_platform_version(version, major_increment, minor_increment, patch_increment, instance_type, vpc=None, staged=False, timeout=None): _raise_if_directory_is_empty() _raise_if_platform_definition_file_is_missing() version and _raise_if_version_format_is_invalid(version) platform_name = fileoperations.get_platform_name() instance_profile = fileoperations.get_instance_profile(None) key_name = commonops.get_default_keyname() version = version or _resolve_version_number( platform_name, major_increment, minor_increment, patch_increment) source_control = SourceControl.get_source_control() io.log_warning(strings['sc.unstagedchanges'] ) if source_control.untracked_changes_exist() else None version_label = _resolve_version_label(source_control, staged) bucket, key, file_path = _resolve_s3_bucket_and_key( platform_name, version_label, source_control, staged) _upload_platform_version_to_s3_if_necessary(bucket, key, file_path) io.log_info('Creating Platform Version ' + version_label) response = elasticbeanstalk.create_platform_version( platform_name, version, bucket, key, instance_profile, key_name, instance_type, vpc) environment_name = 'eb-custom-platform-builder-packer' io.echo( colored( strings['platformbuildercreation.info'].format(environment_name), attrs=['reverse'])) fileoperations.update_platform_version(version) commonops.set_environment_for_current_branch(environment_name) stream_platform_logs(response, platform_name, version, timeout)
def resolve_roles(env_request, interactive): """ Resolves instance-profile and service-role :param env_request: environment request :param interactive: boolean """ LOG.debug('Resolving roles') if (not env_request.instance_profile or env_request.instance_profile == iam_attributes.DEFAULT_ROLE_NAME ) and not env_request.template_name: env_request.instance_profile = commonops.create_default_instance_profile( ) if (env_request.platform and env_request.platform.has_healthd_support and not env_request.service_role and not env_request.template_name): role = get_service_role() if role is None: if interactive: io.echo() io.echo(prompts['create.servicerole.info']) input = io.get_input(prompts['create.servicerole.view'], default='') if input.strip('"').lower() == 'view': for policy_arn in DEFAULT_SERVICE_ROLE_POLICIES: document = iam.get_managed_policy_document(policy_arn) io.echo(json.dumps(document, indent=4)) io.get_input(prompts['general.pressenter']) role = create_default_service_role() env_request.service_role = role
def prompt_for_index_in_list(lst, default=1): lst = list(lst) if default is None: input_text = prompts['common.inputtext'] else: input_text = prompts['common.inputtext.default'].format(default) for x in range(0, len(lst)): io.echo(str(x + 1) + ')', lst[x]) while True: try: default = default or 0 choice = int(io.prompt(input_text, default=default)) if not (0 < choice <= len(lst)): raise ValueError else: break except ValueError: io.echo('Sorry, that is not a valid choice. ' 'Please choose a number between 1 and ' + str(len(lst)) + '.') io.echo() return choice - 1
def prompt_for_solution_stack_version(matching_language_versions): """ Method prompts customer to pick a solution stack version, given a set of platform versions of a language :param matching_language_versions: A list of platform versions of a language to allow the customer to choose from. e.g. Given Platform, Ruby, the following options will be presented 1. Ruby 2.4 (Passenger standalone) 2. Ruby 2.4 (Puma) 3. ... :return: A string representing te platform version the customer would like to use. """ io.echo() io.echo(prompts['sstack.version']) language_versions_to_display = [ version['PlatformShorthand'] for version in matching_language_versions ] return utils.prompt_for_item_in_list(language_versions_to_display)
def update_environment_configuration(app_name, env_name, nohang, timeout=None): # get environment setting api_model = elasticbeanstalk.describe_configuration_settings( app_name, env_name ) # Convert the raw api return to yaml format env_settings = EnvironmentSettings(api_model) usr_model = env_settings.convert_api_to_usr_model() # Save the yaml in a temp file file_location = fileoperations.save_env_file(usr_model) fileoperations.open_file_for_editing(file_location) # Update and delete file try: usr_model = fileoperations.get_environment_from_file(env_name) changes, remove = env_settings.collect_changes(usr_model) if api_model['SolutionStackName'] != usr_model['SolutionStackName']: solution_name = usr_model['SolutionStackName'] else: solution_name = None fileoperations.delete_env_file(env_name) except InvalidSyntaxError: io.log_error(prompts['update.invalidsyntax']) return if not changes and not remove and not solution_name: # no changes made, exit io.log_warning('No changes made. Exiting.') return if fileoperations.env_yaml_exists(): io.echo(strings['config.envyamlexists']) commonops.update_environment(env_name, changes, nohang, remove=remove, timeout=timeout, solution_stack_name=solution_name)
def _get_cloudwatch_messages(log_group_name, stream_name, formatter=None, next_token=None, start_time=None): messages = [] response = None latest_event_timestamp = start_time try: response = cloudwatch.get_log_events(log_group_name, stream_name, next_token=next_token, start_time=start_time) except MaxRetriesError as e: LOG.debug('Received max retries') io.echo(e.message()) time.sleep(1) if response and response.get('events'): for event in response.get('events'): message = event.get('message').encode('utf8', 'replace') if formatter: timestamp = event.get('timestamp') if timestamp: latest_event_timestamp = timestamp formatted_message = formatter.format(message, stream_name) else: formatted_message = '[{1}] {0}'.format(message, stream_name) messages.append(formatted_message) # Set the next token next_token = response.get('nextForwardToken') return messages, next_token, latest_event_timestamp
def prompt_for_platform_branch(family): branches = platform_branch_ops.list_nonretired_platform_branches() branches = [branch for branch in branches if branch['PlatformName'] == family] branches = _sort_platform_branches_for_prompt(branches) if len(branches) == 1: return PlatformBranch.from_platform_branch_summary(branches[0]) branch_display_names = [_generate_platform_branch_prompt_text(branch) for branch in branches] default = utils.index_of( branches, value=platform_branch_lifecycle_states.SUPPORTED, key=lambda b: b['LifecycleState']) if default == -1: default = None else: default += 1 io.echo(prompts['platformbranch.prompt']) index = utils.prompt_for_index_in_list(branch_display_names, default=default) return PlatformBranch.from_platform_branch_summary(branches[index])
def retrieve_beanstalk_logs(env_name, info_type, do_zip=False, instance_id=None): """ Obtains the set of logs from ElasticBeanstalk for the environment `env_name`. :param env_name: An Elastic Beanstalk environment name :param info_type: The type of information to request. Possible values: tail, bundle :param do_zip: Whether the information retrieved should be zipped; works only with info_type 'bundle' :param instance_id: The specific EC2 instance associated with `env_name` whose log information to retrieve :return: None """ result = elasticbeanstalk.request_environment_info(env_name, info_type) request_id = result['ResponseMetadata']['RequestId'] io.echo(prompts['logs.retrieving']) commonops.wait_for_success_events( request_id, timeout_in_minutes=2, sleep_time=1, stream_events=False ) get_logs(env_name, info_type, do_zip=do_zip, instance_id=instance_id)
def create_env(env_request, interactive=True): if env_request.template_name: platform = env_request.platform env_request.platform = None else: platform = None while True: try: return elasticbeanstalk.create_environment(env_request) except InvalidParameterValueError as e: if e.message == responses['app.notexists'].replace( '{app-name}', '\'' + env_request.app_name + '\''): commonops.create_app(env_request.app_name) elif e.message == responses['create.noplatform']: if platform: env_request.platform = platform else: raise elif interactive: LOG.debug('creating env returned error: ' + e.message) if re.match(responses['env.cnamenotavailable'], e.message): io.echo(prompts['cname.unavailable']) io.prompt_for_cname() elif re.match(responses['env.nameexists'], e.message): io.echo(strings['env.exists']) current_environments = elasticbeanstalk.get_all_environment_names( ) unique_name = utils.get_unique_name( env_request.env_name, current_environments) env_request.env_name = io.prompt_for_environment_name( default_name=unique_name) elif e.message == responses['app.notexists'].replace( '{app-name}', '\'' + env_request.app_name + '\''): commonops.create_app(env_request.app_name) else: raise else: raise
def print_list_in_columns(lst): """ This function is currently only intended for environmant names, which are guaranteed to be 23 characters or less. :param lst: List of env names """ if sys.stdout.isatty(): lst = list_to_columns(lst) index = 0 for x in range(0, len(lst[0])): line = [] for i in range(0, len(lst)): try: line.append(lst[i][x]) except IndexError: pass io.echo_and_justify(42, *line) else: # Dont print in columns if using pipe for i in lst: io.echo(i)
def enable_cloudwatch_logs(app_name, env_name, cloudwatch_log_source): """ Enables CloudWatch log-streaming for the given environment if the required streaming of the specified `cloudwatch_log_source`s is not already enabled :param app_name: application name :param env_name: environment name :param cloudwatch_log_source: the source of logs. Defaults to 'instance' if value is 'None'. Use - 'instance' to enable instance log0streaming - 'health' to enable health transition log-streaming - 'all': enable streaming of all CloudWatch log sources :return None """ cloudwatch_log_source = cloudwatch_log_source or logs_operations_constants.LOG_SOURCES.INSTANCE_LOG_SOURCE configuration_settings = elasticbeanstalk.describe_configuration_settings(app_name, env_name) option_settings = [] timeout = 5 if cloudwatch_log_source in [ logs_operations_constants.LOG_SOURCES.ALL_LOG_SOURCES, logs_operations_constants.LOG_SOURCES.INSTANCE_LOG_SOURCE ]: if not instance_log_streaming_enabled(app_name, env_name, config_settings=configuration_settings): timeout = 15 option_settings.append(_instance_log_streaming_option_setting()) io.echo(strings['cloudwatch_instance_log_streaming.enable']) else: io.echo(strings['cloudwatch_instance_log_streaming.already_enabled']) if cloudwatch_log_source in [ logs_operations_constants.LOG_SOURCES.ALL_LOG_SOURCES, logs_operations_constants.LOG_SOURCES.ENVIRONMENT_HEALTH_LOG_SOURCE, ]: _raise_if_environment_is_not_using_enhanced_health(configuration_settings) if not environment_health_streaming_enabled(app_name, env_name, config_settings=configuration_settings): option_settings.append(_environment_health_log_streaming_option_setting()) io.echo(strings['cloudwatch_environment_health_log_streaming.enable']) else: io.echo(strings['cloudwatch_environment_health_log_streaming.already_enabled']) if not option_settings: return _echo_link_to_cloudwatch_console(env_name) commonops.update_environment(env_name, changes=option_settings, nohang=False, timeout=timeout)
def delete_app_version_label(app_name, version_label): if version_label: app_versions = elasticbeanstalk.get_application_versions( app_name)['ApplicationVersions'] if not any(version_label == app_version['VersionLabel'] for app_version in app_versions): raise ValidationError(strings['appversion.delete.notfound'].format( app_name, version_label)) envs = elasticbeanstalk.get_app_environments(app_name) versions_in_use = [(e.version_label, e.name) for e in envs] used_envs = [ version[1] for version in versions_in_use if version[0] == version_label ] if used_envs: raise ValidationError(strings['appversion.delete.deployed'].format( version_label, ','.join(used_envs))) should_delete = io.get_boolean_response( text=prompts['appversion.delete.validate'].format(version_label), default=True) if not should_delete: io.echo('Application Version will not be deleted.') delete_successful = False else: elasticbeanstalk.delete_application_version( app_name, version_label) io.echo('Application Version deleted successfully.') delete_successful = True return delete_successful else: raise NotFoundError(strings['appversion.delete.none'])
def stream_build_configuration_app_version_creation(app_name, app_version_label, build_spec): # Get the CloudWatch logs link successfully_generated = wait_for_app_version_attribute( app_name, [app_version_label], 'BuildArn', timeout=1) app_version_response = elasticbeanstalk.get_application_versions( app_name, version_labels=[app_version_label])['ApplicationVersions'] build_response = codebuild.batch_get_builds([app_version_response[0]['BuildArn']]) \ if successfully_generated else None codebuild_timeout = build_spec.timeout or 60 if build_response is not None and 'logs' in build_response['builds'][0]: log_link_text = strings['codebuild.buildlogs'].replace( '{logs_link}', build_response['builds'][0]['logs']['deepLink']) io.echo(log_link_text) io.echo( "NOTE: The CodeBuild timeout is set to {0} minutes, so this operation may take upto '{0}' minutes to complete." .format(codebuild_timeout)) else: io.log_warning("Could not retrieve CloudWatch link for CodeBuild logs") # Wait for the success events try: from ebcli.operations.commonops import wait_for_success_events wait_for_success_events(None, timeout_in_minutes=codebuild_timeout, can_abort=False, version_label=app_version_label) except ServiceError as exception: LOG.debug( "Caught service error while creating application version '{0}' " "deleting the created application version as it is useless now.". format(app_version_label)) elasticbeanstalk.delete_application_version(app_name, app_version_label) raise exception
def wait_for_app_version_attribute(app_name, version_labels, attribute, timeout=5): versions_to_check = list(version_labels) found = {} failed = {} io.echo('--- Waiting for Application Versions to populate attributes ---') for version in version_labels: found[version] = False failed[version] = False start_time = datetime.utcnow() while not all([(found[version] or failed[version]) for version in versions_to_check]): if datetime.utcnow() - start_time >= timedelta(minutes=timeout): io.log_error(strings['appversion.attributefailed']) return False io.LOG.debug('Retrieving app versions.') app_versions = elasticbeanstalk.get_application_versions(app_name, versions_to_check) for v in app_versions: if attribute in v: if v[attribute] is not None: found[v['VersionLabel']] = True io.echo('Found needed attributes for application version {}' .format(v['VersionLabel'])) versions_to_check.remove(v['VersionLabel']) elif 'Status' in v and (v['Status'] == 'FAILED' or v['Status'] == 'FAILED'): failed[v['VersionLabel']] = True io.log_error(strings['appversion.attributefailed'].replace('{app_version}', v['VersionLabel'])) versions_to_check.remove(v['VersionLabel']) if all(found.values()): return True time.sleep(4) if any(failed.values()): return False return True
def _generate_and_upload_keypair(keys): # Get filename io.echo() io.echo(prompts['keypair.nameprompt']) unique = utils.get_unique_name('aws-eb', keys) keyname = io.prompt('Default is ' + unique, default=unique) file_name = fileoperations.get_ssh_folder() + keyname try: exitcode = subprocess.call( ['ssh-keygen', '-f', file_name, '-C', keyname]) except OSError: raise CommandError(strings['ssh.notpresent']) if exitcode == 0 or exitcode == 1: # if exitcode is 1, they file most likely exists, and they are ## just uploading it commonops.upload_keypair_if_needed(keyname) return keyname else: LOG.debug('ssh-keygen returned exitcode: ' + str(exitcode) + ' with filename: ' + file_name) raise CommandError('An error occurred while running ssh-keygen.')
def should_prompt_customer_to_opt_into_codecommit( force_non_interactive, region_name, source ): source_location, repository, branch = utils.parse_source(source) if force_non_interactive: return False elif not codecommit.region_supported(): if source_location: io.log_warning(strings['codecommit.badregion']) return False elif not fileoperations.is_git_directory_present(): io.echo(strings['codecommit.nosc']) return False elif not fileoperations.program_is_installed('git'): io.echo(strings['codecommit.nosc']) return False elif directory_is_already_associated_with_a_branch(): return False return True
def do_command(self): app_name = self.get_app_name() env_name = self.get_env_name(noerror=True) provided_env_name = bool(self.app.pargs.environment_name) if not provided_env_name: # Ask interactively for an env to abort envs = abortops.get_abortable_envs(app_name) if len(envs) < 1: raise NotFoundError(strings['abort.noabortableenvs']) if len(envs) == 1: # Don't ask for env, just abort only abortable environment env_name = envs[0].name else: # Ask for env to abort io.echo() io.echo(prompts['abort.envprompt']) env_name = utils.prompt_for_item_in_list(envs).name else: # Just do the abort if env_name is provided pass abortops.abort_operation(env_name)
def enable_cloudwatch_logs(env_name): # Add option settings needed for log streaming """ Enables cloudwatch log streaming for the given environment :param env_name: environment name """ option_settings = [ elasticbeanstalk.create_option_setting( namespaces.CLOUDWATCH_LOGS, option_names.STREAM_LOGS, 'true' ), ] io.echo(strings['cloudwatch-logs.enable']) # echo link to cloudwatch console, BJS console link is different region = commonops.get_default_region() if region == 'cn-north-1': cw_link_regionalized = strings['cloudwatch-logs.bjslink'] else: cw_link_regionalized = strings['cloudwatch-logs.link'] io.echo(cw_link_regionalized.replace('{region}', region).replace('{env_name}', env_name)) commonops.update_environment(env_name, changes=option_settings, nohang=False)
def do_command(self): app_name = self.get_app_name() source_env = self.get_env_name() destination_env = self.app.pargs.destination_name if not destination_env: # Ask interactively for an env to swap with envs = elasticbeanstalk.get_environment_names(app_name) if len(envs) < 2: raise NotSupportedError(strings['swap.unsupported']) # Filter out current env envs = [e for e in envs if e != source_env] if len(envs) == 1: # Don't ask for env, just swap with only other environment destination_env = envs[0] else: # Ask for env to swap with io.echo() io.echo(prompts['swap.envprompt']) destination_env = utils.prompt_for_item_in_list(envs) swapops.cname_swap(source_env, destination_env)
def update_environment(env_name, changes, nohang, remove=None, template=None, timeout=None, template_body=None, solution_stack_name=None, platform_arn=None): try: request_id = elasticbeanstalk.update_environment( env_name, changes, remove=remove, template=template, template_body=template_body, solution_stack_name=solution_stack_name, platform_arn=platform_arn) except InvalidStateError: io.log_error(prompts['update.invalidstate']) return except InvalidSyntaxError as e: io.log_error(prompts['update.invalidsyntax'] + '\nError = ' + e.message) return if nohang: return io.echo('Printing Status:') wait_for_success_events(request_id, timeout_in_minutes=timeout, can_abort=True)
def get_quick_link(app_name, env_name): env = elasticbeanstalk.get_environment(app_name=app_name, env_name=env_name) settings = elasticbeanstalk.describe_configuration_settings( app_name, env_name) option_settings = settings['OptionSettings'] environment_type = elasticbeanstalk.get_option_setting( option_settings, 'aws:elasticbeanstalk:environment', 'EnvironmentType') instance_type = elasticbeanstalk.get_option_setting( option_settings, 'aws:autoscaling:launchconfiguration', 'InstanceType') link = 'https://console.aws.amazon.com/elasticbeanstalk/home?' region = aws.get_region_name() link += 'region=' + urllib.parse.quote(region) link += '#/newApplication' link += '?applicationName=' + urllib.parse.quote(app_name) link += '&solutionStackName=' + urllib.parse.quote( env.platform.platform_shorthand) link += '&tierName=' + env.tier.name if environment_type: link += '&environmentType=' + environment_type if env.version_label: app_version = elasticbeanstalk.get_application_versions( app_name, version_labels=[env.version_label])['ApplicationVersions'][0] source_bundle = app_version['SourceBundle'] source_url = 'https://s3.amazonaws.com/' + source_bundle['S3Bucket'] + \ '/' + source_bundle['S3Key'] link += '&sourceBundleUrl=' + source_url if instance_type: link += '&instanceType=' + instance_type link = _add_database_options(link, option_settings) link = _add_vpc_options(link, option_settings) io.echo(link)
def do_command(self): version = self.app.pargs.version stream = self.app.pargs.stream if version is None: platform_name = fileoperations.get_platform_name() version = fileoperations.get_platform_version() else: platform_name = fileoperations.get_platform_name() if VALID_PLATFORM_VERSION_FORMAT.match(version): pass elif PlatformVersion.is_valid_arn(version): _, platform_name, version = PlatformVersion.arn_to_platform( version) elif VALID_PLATFORM_SHORT_FORMAT.match(version): match = VALID_PLATFORM_SHORT_FORMAT.match(version) platform_name, version = match.group(1, 2) else: raise InvalidPlatformVersionError( strings['exit.invalidversion']) io.echo('Retrieving logs...') if stream: try: logsops.stream_platform_logs( platform_name, version, log_name="%s/%s" % (platform_name, version), # Packer is our only builder type at this point formatter=platformops.PackerStreamFormatter()) except NotFoundError: raise NotFoundError('Unable to find logs in CloudWatch.') else: # print with paginator paginate_cloudwatch_logs(platform_name, version)