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 test_log_error__debug_mode( self, ebglobals_mock ): ebglobals_mock.app.pargs.debug = True io.log_error('hello, world!') ebglobals_mock.app.log.error.asswert_called_once_with()
def get_env_name(self, cmd_example=None, noerror=False, varname='environment_name'): env_name = getattr(self.app.pargs, varname, None) if not env_name: env_name = commonops. \ get_current_branch_environment() workspace_type = fileoperations.get_workspace_type( Constants.WorkSpaceTypes.APPLICATION) if not env_name: if Constants.WorkSpaceTypes.PLATFORM == workspace_type: raise EBCLIException(strings['platform.nobuilderenv']) if noerror: return None if not cmd_example: message = strings['branch.noenv'].replace( '{cmd}', self.Meta.label) else: message = strings['branch.noenv'].replace( 'eb {cmd}', cmd_example) io.log_error(message) raise NoEnvironmentForBranchError() return env_name
def interactive_update_lifcycle_policy(app_name): api_model = elasticbeanstalk.describe_application(app_name) lifecycle_config = LifecycleConfiguration(api_model) usr_model = lifecycle_config.convert_api_to_usr_model() file_location = fileoperations.save_app_file(usr_model) fileoperations.open_file_for_editing(file_location) 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: io.log_warning(strings['lifecycle.updatenochanges']) return elasticbeanstalk.update_application_resource_lifecycle( app_name, config_changes) io.echo(strings['lifecycle.success'])
def initialize_codecommit(): source_control = SourceControl.get_source_control() try: source_control_setup = source_control.is_setup() except CommandError: source_control_setup = False if not source_control_setup: io.log_error( "Cannot setup CodeCommit because there is no Source Control setup") return if codecommit.region_supported(): codecommit_setup = print_current_codecommit_settings() if codecommit_setup: should_continue = io.get_boolean_response( text='Do you wish to continue?', default=True) if not should_continue: return source_control.setup_codecommit_cred_config() from ebcli.controllers import initialize repository = initialize.get_repository_interactive() branch = initialize.get_branch_interactive(repository) set_repo_default_for_current_environment(repository) set_branch_default_for_current_environment(branch) else: io.log_error("The region {0} is not supported by CodeCommit".format( aws.get_region_name()))
def paginate_cloudwatch_logs(platform_name, version, formatter=None): log_group_name = _get_platform_builder_group_name(platform_name) next_token = None start_time = None while True: try: messages, next_token, start_time = get_cloudwatch_messages( log_group_name, version, formatter, next_token, start_time) if messages: io.echo_with_pager("\n".join(messages)) else: break except ServiceError as e: # Something went wrong getting the stream # It probably doesnt exist anymore. io.log_error(e) break except Exception as e: # We want to swallow all exceptions or else they will be # printed as a stack trace to the Console # Exceptions are typically connections reset and # Various things LOG.debug('Exception raised: ' + str(e)) LOG.debug(traceback.format_exc())
def initialize_codecommit(): source_control = SourceControl.get_source_control() try: source_control_setup = source_control.is_setup() except CommandError: source_control_setup = False if not source_control_setup: io.log_error("Cannot setup CodeCommit because there is no Source Control setup") return if codecommit.region_supported(commonops.get_default_region()): # Show the current setup if there is one and ask if they want to continue codecommit_setup = print_current_codecommit_settings() if codecommit_setup: try: io.validate_action("Do you wish to continue (y/n)", "y") except ValidationError: return # Setup git config settings for code commit credentials source_control.setup_codecommit_cred_config() # Get user desired repository from ebcli.controllers import initialize repository = initialize.get_repository_interactive() branch = initialize.get_branch_interactive(repository) # set defaults for current environment set_repo_default_for_current_environment(repository) set_branch_default_for_current_environment(branch) else: io.log_error("The region {0} is not supported by CodeCommit".format(commonops.get_default_region()))
def initialize_codecommit(): source_control = SourceControl.get_source_control() try: source_control_setup = source_control.is_setup() except CommandError: source_control_setup = False if not source_control_setup: io.log_error("Cannot setup CodeCommit because there is no Source Control setup") return if codecommit.region_supported(commonops.get_default_region()): # Show the current setup if there is one and ask if they want to continue codecommit_setup = print_current_codecommit_settings() if codecommit_setup: try: io.validate_action("Do you wish to continue (y/n)", "y") except ValidationError: return # Setup git config settings for code commit credentials source_control.setup_codecommit_cred_config() # Get user desired repository from ..controllers import initialize repository = initialize.get_repository_interactive() branch = initialize.get_branch_interactive(repository) # set defaults for current environment set_repo_default_for_current_environment(repository) set_branch_default_for_current_environment(branch) else: io.log_error("The region {0} is not supported by CodeCommit".format(commonops.get_default_region()))
def get_env_name(self, cmd_example=None, noerror=False, varname='environment_name'): # Try to get env_name from args using varname, if not found, env_name is None here env_name = getattr(self.app.pargs, varname, None) if not env_name: # If env name not provided, grab branch default env_name = commonops. \ get_current_branch_environment() workspace_type = fileoperations.get_workspace_type(Constants.WorkSpaceTypes.APPLICATION) if not env_name: if Constants.WorkSpaceTypes.PLATFORM == workspace_type: raise EBCLIException(strings['platform.nobuilderenv']) # No default env, lets ask for one if noerror: return None if not cmd_example: message = strings['branch.noenv'].replace('{cmd}', self.Meta.label) else: message = strings['branch.noenv'].replace('eb {cmd}', cmd_example) io.log_error(message) raise NoEnvironmentForBranchError() return env_name
def test_log_error(self, echo_mock, ebglobals_mock): ebglobals_mock.app.pargs.debug = False io.log_error('hello, world!') ebglobals_mock.app.log.error.assert_not_called() echo_mock.assert_called_once_with('ERROR: hello, world!')
def open_file_for_editing(file_location): file_location = '"{0}"'.format(file_location) editor = get_editor() try: os.system(editor + ' ' + file_location) except OSError: io.log_error(prompts['fileopen.error1'].replace('{editor}', editor))
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 wait_for_app_version_attribute(app_name, version_labels, timeout=5): io.echo('--- Waiting for Application Versions to populate attributes ---') versions_to_check = list(version_labels) found = dict.fromkeys(version_labels) failed = dict.fromkeys(version_labels) start_time = datetime.utcnow() timediff = timedelta(minutes=timeout) while versions_to_check: if _timeout_reached(start_time, timediff): io.log_error(strings['appversion.attribute.failed'].replace( '{app_version}', ', '.join(version_labels))) return False io.LOG.debug('Retrieving app versions.') app_versions = elasticbeanstalk.get_application_versions( app_name, versions_to_check)['ApplicationVersions'] for version in app_versions: if version.get('BuildArn'): found[version['VersionLabel']] = True io.echo(strings['appversion.attribute.success'].format( app_version=version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) elif version.get('Status') == 'FAILED': failed[version['VersionLabel']] = True io.log_error(strings['appversion.attribute.failed'].format( app_version=version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) if all(found.values()): return True _sleep() return not any(failed.values())
def stream_single_stream(log_group_name, stream_name, streamer, sleep_time=4, formatter=None): next_token = None while True: try: messages = None messages, next_token = get_cloudwatch_messages(log_group_name, stream_name, formatter, next_token) except ServiceError as e: # Something went wrong getting the stream # It probably doesnt exist anymore. io.log_error(e) return except CaughtSignal: break except Exception as e: # Wait a bit before retrying time.sleep(0.5) # We want to swallow all exceptions or else they will be # printed as a stack trace to the Console # Exceptions are typically connections reset and # Various things LOG.debug('Exception raised: ' + str(e)) # Loop will cause a retry if messages: for message in messages: streamer.stream_event(message) time.sleep(0.1) else: time.sleep(sleep_time)
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 test_log_error__cement_app_not_initialized_yet( self, echo_mock, ebglobals_mock ): io.log_error('hello, world!') echo_mock.assert_called_once_with('ERROR: hello, world!')
def do_command(self): try: platformops.get_version_status(self.app.pargs.version) except InvalidPlatformVersionError: if not self.app.pargs.version: io.log_error("This workspace is currently associated with a deleted version.") else: raise InvalidPlatformVersionError(strings['exit.nosuchplatformversion'])
def open_file_for_editing(file_location): # Added this line for windows whitespace escaping file_location = '"{0}"'.format(file_location) editor = get_editor() try: os.system(editor + ' ' + file_location) except OSError: io.log_error(prompts['fileopen.error1'].replace('{editor}', editor))
def get(self): app_name = self.get_app_name() name = self._get_cfg_name('get') try: saved_configs.download_config_from_s3(app_name, name) except NotFoundError: io.log_error(strings['config.notfound'].replace( '{config-name}', name))
def credentials_are_valid(): try: elasticbeanstalk.get_available_solution_stacks(fail_on_empty_response=False) return True except CredentialsError: return False except NotAuthorizedError as e: io.log_error('The current user does not have the correct permissions. ' 'Reason: {0}'.format(e.message)) return False
def _raise_if_none(self, value, default_value, error_message): """ Return value if it is not None. If value is None, return default_value if it is not None. If default_Value is also None, raise an error. """ if value is not None: return value elif default_value is not None: return default_value else: io.log_error(error_message) sys.exit()
def env_name(self): if self.app.pargs.environment_name: env_name = self.app.pargs.environment_name else: env_name = commonops.get_current_branch_environment() if not env_name: message = strings['branch.noenv'].replace('{cmd}', self.Meta.label) io.log_error(message) raise NoEnvironmentForBranchError() return env_name
def env_name(self): if self.app.pargs.environment_name: env_name = self.app.pargs.environment_name else: env_name = commonops.get_current_branch_environment() if not env_name: message = strings['branch.noenv'].replace('{cmd}', self.Meta.label) io.log_error(message) raise NoEnvironmentForBranchError() return env_name
def open_file_for_editing(file_location): # Added this line for windows whitespace escaping file_location = '"{0}"'.format(file_location) editor = get_editor() try: os.system(editor + ' ' + file_location) except OSError: io.log_error( prompts['fileopen.error1'].replace( '{editor}', editor ) )
def open_file_for_editing(file_location): editor = fileoperations.get_editor() if editor: try: os.system(editor + ' ' + file_location) except OSError: io.log_error(prompts['fileopen.error1'].replace( '{editor}', editor)) else: try: os.system(file_location) except OSError: io.log_error(prompts['fileopen.error2'])
def establish_codecommit_repository(repository, source_control, source_location): if repository is None: repository = get_repository_interactive() else: try: setup_codecommit_remote_repo(repository, source_control) except ServiceError as ex: if source_location: create_codecommit_repository(repository) setup_codecommit_remote_repo(repository, source_control) else: io.log_error(strings['codecommit.norepo']) raise ex return repository
def establish_codecommit_branch(repository, branch, source_control, source_location): if branch is None: branch = get_branch_interactive(repository) else: try: codecommit.get_branch(repository, branch) except ServiceError as ex: if source_location: create_codecommit_branch(source_control, branch) else: io.log_error(strings['codecommit.nobranch']) raise ex source_control.setup_existing_codecommit_branch(branch) return branch
def get_cloudwatch_messages( log_group_name, stream_name, formatter, next_token, start_time, messages_handler, sleep_time=10 ): """ Polls periodically the logStream `stream_name` until interrupted through a KeyboardInterrupt or an unexpected exception :param log_group_name: A CloudWatch logGroup in which the logStream `stream_name` exists :param stream_name: A CloudWatch logStream to poll :param formatter: The object that formats the output to be displayed in the terminal :param next_token: The token for the next set of items to return :param start_time: The start of the time range, expressed as the number of milliseconds after Jan 1, 1970 00:00:00 UTC. Events with a time stamp earlier than this time are not included. :param messages_handler: :param sleep_time: Time in seconds to sleep before polling CloudWatch for newer events :return: None """ while True: try: messages, next_token, start_time = _get_cloudwatch_messages( log_group_name, stream_name, formatter, next_token, start_time ) if messages: messages_handler(messages) else: break except ServiceError as e: io.log_error(e) break except Exception as e: LOG.debug('Exception raised: ' + str(e)) LOG.debug(traceback.format_exc()) except KeyboardInterrupt: break _wait_to_poll_cloudwatch(sleep_time) start_time = _updated_start_time()
def prompt_and_action(self, prompt_string, action): id = '' t = term.get_terminal() io.echo(t.normal_cursor(), end='') # Move cursor to specified empty row with t.location(y=self.empty_row, x=2), t.cbreak(): io.echo(io.bold(prompt_string), end=' ') sys.stdout.flush() val = None while not val or val.name not in {'KEY_ESCAPE', 'KEY_ENTER'}: val = t.inkey(timeout=.5) if val is None: continue elif val.is_sequence is False: id += str(val) sys.stdout.write(str(val)) sys.stdout.flush() elif val.name == 'KEY_DELETE': # Backspace if len(id) > 0: id = id[:-1] sys.stdout.write(str(t.move_left) + t.clear_eol) sys.stdout.flush() term.hide_cursor() if val.name == 'KEY_ESCAPE' or not id: return False with t.location(y=self.empty_row, x=2): sys.stdout.flush() io.echo(t.clear_eol(), end='') try: should_exit_display = action(id) if should_exit_display is None: should_exit_display = True return should_exit_display except (ServiceError, ValidationError, NotFoundError) as e: # Error messages that should be shown directly to user io.log_error(e.message) time.sleep(4) # Leave screen stable for a little return False except (IndexError, InvalidOperation, ValueError) as e: if self.poller.all_app_versions: # Error thrown in versions table max_input = len(self.poller.all_app_versions) io.log_error("Enter a number between 1 and " + str(max_input) + ".") else: io.log_error(e) time.sleep(4) return False except CaughtSignal as sig: if sig.signum == 2: LOG.debug("Caught SIGINT and exiting gracefully from action") return True except Exception as e: # Should never get thrown LOG.debug("Exception thrown: {0},{1}. Something strange happened and the request could not be completed." .format(type(e), e.message)) io.log_error("Something strange happened and the request could not be completed.") time.sleep(4) return False
def prompt_and_action(self, prompt_string, action): id = '' t = term.get_terminal() io.echo(t.normal_cursor(), end='') # Move cursor to specified empty row with t.location(y=self.empty_row, x=2), t.cbreak(): io.echo(io.bold(prompt_string), end=' ') sys.stdout.flush() val = None while not val or val.name not in {'KEY_ESCAPE', 'KEY_ENTER'}: val = t.inkey(timeout=.5) if val is None: continue elif val.is_sequence is False: id += str(val) sys.stdout.write(str(val)) sys.stdout.flush() elif val.name == 'KEY_DELETE': # Backspace if len(id) > 0: id = id[:-1] sys.stdout.write(str(t.move_left) + t.clear_eol) sys.stdout.flush() term.hide_cursor() if val.name == 'KEY_ESCAPE' or not id: return False with t.location(y=self.empty_row, x=2): sys.stdout.flush() io.echo(t.clear_eol(), end='') try: should_exit_display = action(id) if should_exit_display is None: should_exit_display = True return should_exit_display except (ServiceError, ValidationError, NotFoundError) as e: # Error messages that should be shown directly to user io.log_error(e.message) time.sleep(4) # Leave screen stable for a little return False except (IndexError, InvalidOperation, ValueError) as e: if self.poller.all_app_versions: # Error thrown in versions table max_input = len(self.poller.all_app_versions) io.log_error("Enter a number between 1 and " + str(max_input) + ".") else: io.log_error(e) time.sleep(4) return False except CaughtSignal as sig: if sig.signum == 2: LOG.debug("Caught SIGINT and exiting gracefully from action") return True except Exception as e: # Should never get thrown LOG.debug("Exception thrown: {0},{1}. Something strange happened and the request could not be completed." .format(type(e), e.message)) io.log_error("Something strange happened and the request could not be completed.") time.sleep(4) return False
def prepare_for_ssh(env_name, instance, keep_open, force, setup, number, keyname=None, no_keypair_error_message=None, custom_ssh=None, command=None, timeout=None): if setup: setup_ssh(env_name, keyname, timeout=timeout) return if instance and number: raise InvalidOptionsError(strings['ssh.instanceandnumber']) if not instance: instances = commonops.get_instance_ids(env_name) if number is not None: if number > len(instances) or number < 1: raise InvalidOptionsError('Invalid index number (' + str(number) + ') for environment with ' + str(len(instances)) + ' instances') else: instance = instances[number - 1] elif len(instances) == 1: instance = instances[0] else: io.echo() io.echo('Select an instance to ssh into') instance = utils.prompt_for_item_in_list(instances) try: ssh_into_instance(instance, keep_open=keep_open, force_open=force, custom_ssh=custom_ssh, command=command) except NoKeypairError: if not no_keypair_error_message: no_keypair_error_message = prompts['ssh.nokey'] io.log_error(no_keypair_error_message)
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.attribute.failed'].replace( '{app_version}', version_labels)) return False io.LOG.debug('Retrieving app versions.') app_versions = elasticbeanstalk.get_application_versions( app_name, versions_to_check)['ApplicationVersions'] for version in app_versions: if attribute in version: if version[attribute] is not None: found[version['VersionLabel']] = True io.echo(strings['appversion.attribute.success'].replace( '{app_version}', version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) elif 'Status' in version and (version['Status'] == 'FAILED' or version['Status'] == 'FAILED'): failed[version['VersionLabel']] = True io.log_error(strings['appversion.attribute.failed'].replace( '{app_version}', version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) if all(found.values()): return True time.sleep(4) if any(failed.values()): return False return True
def validate_config_file(app_name, cfg_name, platform): filename = fileoperations.get_filename_without_extension(cfg_name) try: result = elasticbeanstalk.validate_template(app_name, filename) except InvalidParameterValueError as e: if e.message == responses['create.noplatform']: result = elasticbeanstalk.validate_template(app_name, cfg_name, platform=platform) else: raise for m in result['Messages']: severity = m['Severity'] message = m['Message'] if severity == 'error': io.log_error(message) elif severity == 'warning': pass
def ssh(self): aws.set_region(self.region) aws.set_profile(self.profile) if self.environment_name is None: environment_names = get_all_environment_names() if environment_names: error = "Please chose one of the following environment names:\n\n" error += "\n".join(sorted(environment_names)) + "\n" io.log_error(error) else: io.log_error( "The current Elastic Beanstalk application has no environments" ) sys.exit() instances = get_instance_ids(self.environment_name) if len(instances) == 1: instance = instances[0] else: io.echo() io.echo('Select an instance to ssh into') instance = utils.prompt_for_item_in_list(instances) params = [ "aws", "ssm", "start-session", "--document-name", "AWS-StartInteractiveCommand", "--parameters", "command='bash -l'", "--profile", self.profile, "--region", self.region, "--target", instance, ] os.system(" ".join(params))
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) platform_arn = None # 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['PlatformArn'] != usr_model['PlatformArn']: platform_arn = usr_model['PlatformArn'] fileoperations.delete_env_file(env_name) except InvalidSyntaxError: io.log_error(prompts['update.invalidsyntax']) return if not changes and not remove and not platform_arn: # 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=None, platform_arn=platform_arn)
def do_command(self): cwfile_dir = CWFILES_DIR_PATH ebextension_dir = fileoperations.project_file_path('.ebextensions') if self.app.pargs.remove: return remove_cwl_extensions(cwfile_dir, ebextension_dir) if not os.path.isdir(ebextension_dir): os.makedirs(ebextension_dir) for file_name in os.listdir(cwfile_dir): source_file = os.path.join(cwfile_dir, file_name) destination = os.path.join(ebextension_dir, file_name) if fileoperations.file_exists(destination): io.log_error(strings['cloudwatch-setup.alreadysetup'] .format(filename=destination)) shutil.copy(source_file, destination) io.echo(strings['cloudwatch-setup.text'])
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) platform_arn = None # 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['PlatformArn'] != usr_model['PlatformArn']: platform_arn = usr_model['PlatformArn'] fileoperations.delete_env_file(env_name) except InvalidSyntaxError: io.log_error(prompts['update.invalidsyntax']) return if not changes and not remove and not platform_arn: # 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=None, platform_arn=platform_arn)
def validate_config_file(app_name, cfg_name, platform): # Get just the name of the file filename = fileoperations.get_filename_without_extension(cfg_name) try: result = elasticbeanstalk.validate_template(app_name, filename) except InvalidParameterValueError as e: # Platform not in Saved config. Try again with default platform if e.message == responses['create.noplatform']: result = elasticbeanstalk.validate_template(app_name, cfg_name, platform=platform) else: raise for m in result['Messages']: severity = m['Severity'] message = m['Message'] if severity == 'error': io.log_error(message) elif severity == 'warning': # Ignore warnings. They are common on partial configurations # and almost always completely irrelevant. # io.log_warning(message) pass
def get_cloudwatch_messages(log_group_name, stream_name, formatter, next_token, start_time, messages_handler, sleep_time=10): """ Polls periodically the logStream `stream_name` until interrupted through a KeyboardInterrupt or an unexpected exception :param log_group_name: A CloudWatch logGroup in which the logStream `stream_name` exists :param stream_name: A CloudWatch logStream to poll :param formatter: The object that formats the output to be displayed in the terminal :param next_token: The token for the next set of items to return :param start_time: The start of the time range, expressed as the number of milliseconds after Jan 1, 1970 00:00:00 UTC. Events with a time stamp earlier than this time are not included. :param messages_handler: :param sleep_time: Time in seconds to sleep before polling CloudWatch for newer events :return: None """ while True: try: messages, next_token, start_time = _get_cloudwatch_messages( log_group_name, stream_name, formatter, next_token, start_time ) if messages: messages_handler(messages) else: break except ServiceError as e: io.log_error(e) break except Exception as e: LOG.debug('Exception raised: ' + str(e)) LOG.debug(traceback.format_exc()) except KeyboardInterrupt: break _wait_to_poll_cloudwatch(sleep_time) start_time = _updated_start_time()
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.attribute.failed'].replace('{app_version}', version_labels)) return False io.LOG.debug('Retrieving app versions.') app_versions = elasticbeanstalk.get_application_versions(app_name, versions_to_check)['ApplicationVersions'] for version in app_versions: if attribute in version: if version[attribute] is not None: found[version['VersionLabel']] = True io.echo(strings['appversion.attribute.success'].replace('{app_version}', version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) elif 'Status' in version and (version['Status'] == 'FAILED' or version['Status'] == 'FAILED'): failed[version['VersionLabel']] = True io.log_error(strings['appversion.attribute.failed'].replace('{app_version}', version['VersionLabel'])) versions_to_check.remove(version['VersionLabel']) if all(found.values()): return True time.sleep(4) if any(failed.values()): return False return True
def do_command(self): # get arguments self.interactive = self.app.pargs.interactive self.region = self.app.pargs.region self.noverify = self.app.pargs.no_verify_ssl self.force_non_interactive = False # Determine if the customer is avoiding interactive mode by setting the platform flag if self.app.pargs.platform: self.force_non_interactive = True # Code Commit integration self.source = self.app.pargs.source source_location = None branch = None repository = None if self.source is not None: source_location, repository, branch = utils.parse_source(self.source) # The user specifies directories to initialize self.modules = self.app.pargs.modules if self.modules and len(self.modules) > 0: self.initialize_multiple_directories() return default_env = self.get_old_values() fileoperations.touch_config_folder() if self.interactive: self.region = get_region(self.region, self.interactive, self.force_non_interactive) else: self.region = get_region_from_inputs(self.region) aws.set_region(self.region) self.region = set_up_credentials(self.app.pargs.profile, self.region, self.interactive) self.solution = self.get_solution_stack() self.app_name = self.get_app_name() if self.noverify: fileoperations.write_config_setting('global', 'no-verify-ssl', True) if not default_env and not self.interactive: # try to get default env from config file if exists try: default_env = commonops.get_current_branch_environment() except NotInitializedError: default_env = None elif self.interactive: default_env = None if self.force_non_interactive: default_env = '/ni' # Create application sstack, key = commonops.pull_down_app_info(self.app_name, default_env=default_env) if elasticbeanstalk.application_exist(self.app_name) \ else commonops.create_app(self.app_name, default_env=default_env) if not self.solution: self.solution = sstack platform_set = False if not self.solution or \ (self.interactive and not self.app.pargs.platform): if fileoperations.env_yaml_exists(): env_yaml_platform = fileoperations.get_platform_from_env_yaml() if env_yaml_platform: platform = solutionstack.SolutionStack(env_yaml_platform).platform_shorthand self.solution = platform platform_set = True if not platform_set: self.solution = solution_stack_ops.get_solution_stack_from_customer().platform_shorthand # Select CodeBuild image if BuildSpec is present do not prompt or show if we are non-interactive if fileoperations.build_spec_exists() and not self.force_non_interactive: build_spec = fileoperations.get_build_configuration() if build_spec is not None and build_spec.image is None: LOG.debug("Buildspec file is present but image is does not exist. Attempting to fill best guess.") platform_image = initializeops.get_codebuild_image_from_platform(self.solution) # If the return is a dictionary then it must be a single image and we can use that automatically if type(platform_image) is dict: io.echo('codebuild.latestplatform'.replace('{platform}', self.solution)) else: # Otherwise we have an array for images which we must prompt the customer to pick from io.echo(prompts['codebuild.getplatform'].replace('{platform}', self.solution)) selected = utils.prompt_for_index_in_list(map(lambda image: image['description'], platform_image)) platform_image = platform_image[selected] platform_image['name'] = utils.decode_bytes(platform_image['name']) # Finally write the CodeBuild image back to the buildspec file fileoperations.write_config_setting(fileoperations.buildspec_config_header, 'Image', platform_image['name'], file=fileoperations.buildspec_name) # Setup code commit integration # Ensure that git is setup source_control = SourceControl.get_source_control() try: source_control_setup = source_control.is_setup() if source_control_setup is None: source_control_setup = False except CommandError: source_control_setup = False default_branch_exists = False if gitops.git_management_enabled() and not self.interactive: default_branch_exists = True # Warn the customer if they picked a region that CodeCommit is not supported codecommit_region_supported = codecommit.region_supported(self.region) if self.source is not None and not codecommit_region_supported: io.log_warning(strings['codecommit.badregion']) # Prompt customer to opt into CodeCommit unless one of the follows holds: if self.force_non_interactive: prompt_codecommit = False elif not codecommit.region_supported(self.region): prompt_codecommit = False elif self.source and source_location.lower() != 'codecommit': # Do not prompt if customer has already specified a code source to # associate the EB workspace with prompt_codecommit = False elif default_branch_exists: # Do not prompt if customer has already configured the EB application # in the present working directory with Git prompt_codecommit = False else: prompt_codecommit = True # Prompt for interactive CodeCommit if prompt_codecommit: if not source_control_setup: io.echo(strings['codecommit.nosc']) else: io.echo(strings['codecommit.ccwarning']) try: if not self.source: io.validate_action(prompts['codecommit.usecc'], "y") # Setup git config settings for code commit credentials source_control.setup_codecommit_cred_config() # Get user specified repository remote_url = None if repository is None: repository = get_repository_interactive() else: try: setup_codecommit_remote_repo(repository, source_control) except ServiceError as ex: if self.source: create_codecommit_repository(repository) setup_codecommit_remote_repo(repository, source_control) else: io.log_error(strings['codecommit.norepo']) raise ex # Get user specified branch if branch is None: branch = get_branch_interactive(repository) else: try: codecommit.get_branch(repository, branch) except ServiceError as ex: if self.source: create_codecommit_branch(source_control, branch) else: io.log_error(strings['codecommit.nobranch']) raise ex source_control.setup_existing_codecommit_branch(branch, remote_url) except ValidationError: LOG.debug("Denied option to use CodeCommit, continuing initialization") # Initialize the whole setup initializeops.setup(self.app_name, self.region, self.solution, dir_path=None, repository=repository, branch=branch) if 'IIS' not in self.solution: self.keyname = self.get_keyname(default=key) if self.keyname == -1: self.keyname = None fileoperations.write_config_setting('global', 'default_ec2_keyname', self.keyname) # Default to including git submodules when creating zip files through `eb create`/`eb deploy`. fileoperations.write_config_setting('global', 'include_git_submodules', True)