text: # Copyright 2017 Google Inc. All Rights Reserved.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  """The main program controller for BomValidate
  
  This program will:
    (1) Deploy Spinnaker as specified via command-line
    (2) Configure Spinnaker as specified via command-line
    (3) Run the test suite or some subset there-of, as specified via command-line
    (4) Collect and report on the results
    (5) Tear down the deployment
  
  
  Sample usage:
  ./validate_bom.sh \
    --deploy_hal_platform=gce \
    --deploy_spinnaker_type=localdebian \
    --deploy_google_project=$PROJECT \
    --deploy_google_instance=$INSTANCE \
    --spinnaker_storage=gcs \
    --storage_gcs_bucket=$BUCKET \
    --google_account_credentials=$GOOGLE_CREDENTIAL_PATH \
    --google_account_project=$PROJECT
  
  //dev/validate_bom.sh \
    --deploy_google_project=$PROJECT \
    --deploy_google_instance=$INSTANCE \
    --spinnaker_storage=gcs \
    --storage_gcs_bucket=$BUCKET \
    --storage_gcs_credentials=$GOOGLE_CREDENTIAL_PATH  \
    --google_account_credentials=$GOOGLE_CREDENTIAL_PATH \
    --google_account_project=$PROJECT \
    --k8s_account_credentials=$HOME/.kube/config \
    --k8s_account_docker_account=my-docker-account \
    --docker_account_address=https://index.docker.io \
    --docker_account_repositories=library/nginx \
    --deploy_hal_platform=gce \
    --deploy_spinnaker_type=distributed \
    --deploy_k8s_namespace=spinnaker \
    --test_include=(kube|front50) \
    --deploy_undeploy=false \
    --deploy_deploy=false
  """
  
  
  import argparse
  import logging
  import os
  import sys
  import yaml
  
  from buildtool.__main__ import (
      STANDARD_LOG_LEVELS,
      preprocess_args,
      add_standard_parser_args)
  from buildtool.metrics import MetricsManager
  from buildtool import (
      add_parser_argument,
      run_subprocess)
  
  
  import validate_bom__config
  import validate_bom__deploy
  import validate_bom__test
  
  
  def build_report(test_controller):
    """Report on the test results."""
    options = test_controller.options
    citest_log_dir = os.path.join(options.log_dir, 'citest_logs')
    if not os.path.exists(citest_log_dir):
      logging.warning('%s does not exist -- no citest logs.', citest_log_dir)
      return None
  
    retcode, stdout = run_subprocess(
        'python -m citest.reporting.generate_html_report --index *.journal',
        shell=True,
        cwd=citest_log_dir)
  
    if retcode != 0:
      logging.error('Error building report: %s', stdout)
    logging.info('Logging information is in %s', options.log_dir)
  
    return test_controller.build_summary()
  
  
  def get_options(args):
    """Resolve all the command-line options."""
  
    args, defaults = preprocess_args(
        args, default_home_path_filename='validate_bom.yml')
  
    parser = argparse.ArgumentParser(prog='validate_bom.sh')
    add_standard_parser_args(parser, defaults)
  # DEPRECATED - use output_dir instead
    add_parser_argument(parser, 'log_dir', defaults, './validate_bom_results',
                        help='Path to root directory for report output.')
  
    MetricsManager.init_argument_parser(parser, defaults)
    validate_bom__config.init_argument_parser(parser, defaults)
    validate_bom__deploy.init_argument_parser(parser, defaults)
    validate_bom__test.init_argument_parser(parser, defaults)
  
    options = parser.parse_args(args)
    options.program = 'validate_bom'
    options.command = 'validate_bom'        # metrics assumes a "command" value.
    options.log_dir = options.output_dir    # deprecated
    validate_bom__config.validate_options(options)
    validate_bom__test.validate_options(options)
  
    if not os.path.exists(options.log_dir):
      os.makedirs(options.log_dir)
  
    if options.influxdb_database == 'SpinnakerBuildTool':
      options.influxdb_database = 'SpinnakerValidate'
  
    # Add platform/spinnaker_type to each metric we produce.
    # We'll use this to distinguish what was being tested.
    context_labels = 'platform=%s,deployment_type=%s' % (
        validate_bom__deploy.determine_deployment_platform(options),
        options.deploy_spinnaker_type)
    latest_unvalidated_suffix = '-latest-unvalidated'
    if options.deploy_version.endswith(latest_unvalidated_suffix):
      bom_series = options.deploy_version[:-len(latest_unvalidated_suffix)]
    else:
      bom_series = options.deploy_version[:options.deploy_version.rfind('-')]
    context_labels += ',version=%s' % bom_series
  
    if options.monitoring_context_labels:
      context_labels += ',' + options.monitoring_context_labels
    options.monitoring_context_labels = context_labels
  
    return options
  
  
  def main(options, metrics):
    """The main controller."""
    outcome_success = False
    deployer = validate_bom__deploy.make_deployer(options, metrics)
    test_controller = validate_bom__test.ValidateBomTestController(deployer)
    if options.deploy_deploy:
      validate_bom__config.setup_environment(options)
    init_script, config_script = validate_bom__config.make_scripts(options)
    file_set = validate_bom__config.get_files_to_upload(options)
  
    try:
      deployer.deploy(init_script, config_script, file_set)
      _, failed, _ = test_controller.run_tests()
      outcome_success = not failed
    finally:
      if sys.exc_info()[0] is not None:
        logging.error('Caught Exception')
        logging.exception('Caught Exception')
      if options.deploy_undeploy or options.deploy_always_collect_logs:
        deployer.collect_logs()
      if options.deploy_undeploy:
        try:
          deployer.undeploy()
        finally:
          validate_bom__config.teardown_environment(options)
      else:
        logging.info('Skipping undeploy because --deploy_undeploy=false')
  
      summary = build_report(test_controller)
      if summary:
        print(summary)
  
      if options.testing_enabled or not outcome_success:
        # Only record the outcome if we were testing
        # or if we failed [to deploy/undeploy].
        metrics.inc_counter('ValidationControllerOutcome',
                            {'success': outcome_success})
  
    logging.info('Exiting with code=%d', test_controller.exit_code)
    return test_controller.exit_code
  
  
  def wrapped_main():
    options = get_options(sys.argv[1:])
  
    logging.basicConfig(
        format='%(levelname).1s %(asctime)s.%(msecs)03d'
               ' [%(threadName)s.%(process)d] %(message)s',
        datefmt='%H:%M:%S',
        level=STANDARD_LOG_LEVELS[options.log_level])
  
    logging.debug(
        'Running with options:\n   %s',
        '\n   '.join(yaml.dump(vars(options), default_flow_style=False)
                     .split('\n')))
  
    metrics = MetricsManager.startup_metrics(options)
    try:
      return main(options, metrics)
    finally:
      MetricsManager.shutdown_metrics()
  
  
  if __name__ == '__main__':
    sys.exit(wrapped_main())
  