def add_app(self, func_name, app_info): """Add a configuration for a new streamalert app integration function Args: app_info (dict): The necessary values needed to begin configuring a new app integration Returns: bool: False if errors occurred, True otherwise """ exists, prompt_for_auth, overwrite = False, True, False app = StreamAlertApp.get_app(app_info['type']) cluster_name = app_info['cluster'] app_name = app_info['app_name'] # Check to see if there is an existing configuration for this app integration cluster_config = self.config['clusters'][cluster_name] if func_name in cluster_config['modules'].get('streamalert_apps', {}): prompt = ( 'An app with the name \'{}\' is already configured for cluster ' '\'{}\'. Would you like to update the existing app\'s configuration' '?'.format(app_name, cluster_name)) exists = True # Return if the user is not deliberately updating an existing config if not continue_prompt(message=prompt): return prompt = ( 'Would you also like to update the authentication information for ' 'app integration with name \'{}\'?'.format(app_name)) # If this is true, we shouldn't prompt again to warn about overwriting prompt_for_auth = overwrite = continue_prompt(message=prompt) if prompt_for_auth and not save_app_auth_info(app, app_info, func_name, overwrite): return False apps_config = cluster_config['modules'].get('streamalert_apps', {}) if not exists: # Save a default app settings to the config for new apps new_app_config = { 'app_name': app_info['app_name'], 'concurrency_limit': 2, 'log_level': 'info', 'log_retention_days': 14, 'memory': app_info['memory'], 'metric_alarms': { 'errors': { 'enabled': True, 'evaluation_periods': 1, 'period_secs': 120 } }, 'schedule_expression': app_info['schedule_expression'], 'timeout': app_info['timeout'], 'type': app_info['type'] } apps_config[func_name] = new_app_config else: # Allow for updating certain attributes for the app without overwriting # current parts of the configuration updated_app_config = { 'memory': app_info['memory'], 'schedule_expression': app_info['schedule_expression'], 'timeout': app_info['timeout'] } apps_config[func_name].update(updated_app_config) cluster_config['modules']['streamalert_apps'] = apps_config # Add this service to the sources for this app integration # The `streamalert_app` is purposely singular here app_sources = self.config['clusters'][cluster_name][ 'data_sources'].get('streamalert_app', {}) app_sources[func_name] = [app.service()] self.config['clusters'][cluster_name]['data_sources'][ 'streamalert_app'] = app_sources LOGGER.info( 'Successfully added \'%s\' app integration to \'conf/clusters/%s.json\' ' 'for service \'%s\'.', app_info['app_name'], app_info['cluster'], app_info['type']) self.write() return True
def handler(cls, options, config): """Perform app related functions Args: options (argparse.Namespace): Parsed arguments with info to configure a new app or update an existing one config (CLIConfig): Loaded StreamAlert config Returns: bool: False if errors occurred, True otherwise """ if not options: return False # List all of the available app integrations, broken down by cluster if options.subcommand == 'list': all_info = { cluster: cluster_config['modules'].get('streamalert_apps') for cluster, cluster_config in config['clusters'].items() } for cluster, info in all_info.items(): print('\nCluster: {}\n'.format(cluster)) if not info: print('\tNo Apps configured\n') continue for name, details in info.items(): print('\tName: {}'.format(name)) print('\n'.join([ '\t\t{key}:{padding_char:<{padding_count}}{value}'. format(key=key_name, padding_char=' ', padding_count=30 - (len(key_name)), value=value) for key_name, value in details.items() ] + ['\n'])) return True # Convert the options to a dict app_info = vars(options) # Add the region and prefix for this StreamAlert instance to the app info app_info['region'] = str(config['global']['account']['region']) app_info['prefix'] = str(config['global']['account']['prefix']) # Create a new app integration function if options.subcommand == 'new': function_name = '_'.join([ app_info['prefix'], app_info['cluster'], app_info['type'], app_info['app_name'], 'app' ]) return config.add_app(function_name, app_info) # Update the auth information for an existing app integration function if options.subcommand == 'update-auth': cluster_config = config['clusters'][app_info['cluster']] apps = cluster_config['modules'].get('streamalert_apps', {}) if not apps: LOGGER.error('No apps configured for cluster \'%s\'', app_info['cluster']) return False # Find the appropriate function config for this app func_name = None for function_name, app_config in apps.items(): if app_config.get('app_name') == app_info['app_name']: func_name = function_name break if not func_name: LOGGER.error( 'App with name \'%s\' does not exist for cluster \'%s\'', app_info['app_name'], app_info['cluster']) return False # Get the type for this app integration from the current # config so we can update it properly app_info['type'] = cluster_config['modules']['streamalert_apps'][ func_name]['type'] app = StreamAlertApp.get_app(app_info['type']) if not save_app_auth_info(app, app_info, func_name, True): return False return True