class_docstr: A class to load, modify, and display the StreamAlertCLI Config
docstr: 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
docstr_tok: ["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"]
code: 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
  
imports: import json
  import os
  import re
  import shutil
  import string
  import tempfile
  from streamalert.apps import StreamAlertApp
  from streamalert.shared import CLUSTERED_FUNCTIONS, config, metrics
  from streamalert.shared.logger import get_logger
  from streamalert_cli.terraform import TERRAFORM_FILES_PATH
  from streamalert_cli.apps.helpers import save_app_auth_info
  from streamalert_cli.helpers import continue_prompt
label_desc: Use image node_id 21 for calling the CLIConfig obj's underlying member method code with example usage: obj.add_app(func_name, app_info) and returns: True, False