docstr: 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
docstr_tok: ["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"]
code: 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
  
file_path: streamalert/streamalert_cli/apps/handler.py
imports: import string
  from streamalert.apps import StreamAlertApp
  from streamalert.shared.logger import get_logger
  from streamalert_cli.apps.helpers import save_app_auth_info
  from streamalert_cli.utils import add_memory_arg, add_schedule_expression_arg, add_timeout_arg, CLICommand, CLUSTERS, generate_subparser, set_parser_epilog
label_desc: Use image node_id 6 for calling the AppCommand obj's underlying member method code with example usage: obj.handler(cls, options, config) and returns: False, True, config, True, False, False, False