#!groovy

@Library('infraLib') _

import java.time.LocalDate
import java.time.format.DateTimeFormatter

def source_environments = [
  'images-api.atlas.stream',
  'proxy.apollo.stream/apollo-api',
  'proxy.apollo.stream/dsp-api',
  'proxy.apollo.stream/gate-api',
  'proxy.apollo.stream/user-data-api',
  'proxy.apollo.stream/vendor-api',
]

def target_environments = [
  'same as the logs source',
  'images-api.atlas.stream',
  'proxy.apollo.stream/apollo-api',
  'proxy.apollo.stream/dsp-api',
  'proxy.apollo.stream/gate-api',
  'proxy.apollo.stream/user-data-api',
  'proxy.apollo.stream/vendor-api',
]

def getAwsProfileByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 'gdb-core-prod'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'gdb-apollo-prod'
    default:
      ''
  }
}

def getAthenaDatabaseByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 'security_885200931856_logs'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'security_801577982711_logs'
    default:
        ''
  }
}

def getAthenaResultsBucketByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 's3://prod-core-athena-results/Unsaved/'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 's3://prod-apollo-athena-output/Unsaved/'
    default:
      return ''
  }
}

def getAthenaTableByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 'prod_core_images_api_logs'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'prod_apollo_external_main_logs'
    default:
      return ''
  }
}

def getAthenaLogsTypeByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 'cloudfront'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'elb'
    default:
      return ''
  }
}

def getAthenaUrlFilterPrefixByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return ''
    case 'proxy.apollo.stream/vendor-api':
      return 'https://proxy.apollo.stream:443/vendor-api'
    case 'proxy.apollo.stream/gate-api':
      return 'https://proxy.apollo.stream:443/gate-api'
    case 'proxy.apollo.stream/apollo-api':
      return 'https://proxy.apollo.stream:443/apollo-api'
    case 'proxy.apollo.stream/dsp-api':
      return 'https://proxy.apollo.stream:443/dsp-api'
    case 'proxy.apollo.stream/user-data-api':
      return 'https://proxy.apollo.stream:443/user-data-api'
    default:
      return ''
  }
}

def getAtlasHostByEnvironment(environment) {
  switch (environment) {
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'um.atlas.stream'
    default:
      return ''
  }
}

def getAtlasClientIdByEnvironment(environment) {
  switch (environment) {
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return '6587d6b0-b133-4f6d-b014-7a9e0b14bad4'
    default:
      return ''
  }
}

def getAtlasClientSecretByEnvironment(environment) {
  switch (environment) {
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return utility.getSecretValueByIdAndJsonPath('infra/jenkins/load-tester/ATLAS_CLIENT_SECRET', 'gdb-infra-dev', '.apollo.prod')
    default:
      return ''
  }
}

def getAtlasAudienceByEnvironment(environment) {
  switch (environment) {
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'apollo|api'
    default:
      return ''
  }
}

def getHostByEnvironment(environment) {
  switch (environment) {
    case 'images-api.atlas.stream':
      return 'images-api.atlas.stream'
    case 'proxy.apollo.stream/apollo-api':
    case 'proxy.apollo.stream/dsp-api':
    case 'proxy.apollo.stream/gate-api':
    case 'proxy.apollo.stream/user-data-api':
    case 'proxy.apollo.stream/vendor-api':
      return 'proxy.apollo.stream'
    default:
      return ''
  }
}

def getCurrentDate(){
  def dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd")
  def currentDate = LocalDate.now().format(dateFormat);
  return currentDate
}

String[] URI_METRICS = "throughput concurrency succ fail avg_rt stdev_rt avg_lt avg_ct bytes".split()

pipeline {
  agent {
    label 'linux-agents-xlarge'
  }

  parameters {
    // let's use domains, as there will be the variety of products here
    choice(choices: source_environments,
           name: 'ACCESS_LOGS_SOURCE_ENVIRONMENT',
           description: 'What access logs we should use as a sample')
    choice(choices: target_environments,
           name: 'TARGET_ENVIRONMENT',
           description: 'Target environment.')
    string(defaultValue: getCurrentDate(),
           name: 'current_date',
           trim: true)
    string(defaultValue: "100",
           name: 'NUM_USERS',
           trim: true)
    string(defaultValue: "5",
           name: 'SPAWN_RATE',
           trim: true)
    string(defaultValue: "600s",
           name: 'RUN_TIME',
           trim: true)
    string(defaultValue: "",
           name: 'S3_BUCKET_REQUESTS_EXTRA_CONFIG',
           trim: true)
    string(defaultValue: "",
           name: 'EXTRA_ARGS',
           trim: true)
  }

  environment {
    AWS_PROFILE    = 'gdb-infra-dev'
    AWS_ACCOUNT_ID = '483193324480'
    AWS_REGION     = 'us-east-1'

    ECR_REGISTRY        = "${env.AWS_ACCOUNT_ID}.dkr.ecr.${env.AWS_REGION}.amazonaws.com"
    ECR_REPOSITORY_NAME = 'infra/locust-runner'
    ECR_REGISTRY_URI    = "${env.ECR_REGISTRY}/${ECR_REPOSITORY_NAME}"

    SOURCE_ENVIRONMENT_NAME = params.ACCESS_LOGS_SOURCE_ENVIRONMENT.replace('/', '_')

    S3_BUCKET_REQUESTS_EXTRA_CONFIG = "${params.S3_BUCKET_REQUESTS_EXTRA_CONFIG}"

    TARGET_ENVIRONMENT      ="${params.TARGET_ENVIRONMENT != 'same as the logs source' ? params.TARGET_ENVIRONMENT : params.ACCESS_LOGS_SOURCE_ENVIRONMENT}"
    TARGET_ENVIRONMENT_NAME = env.TARGET_ENVIRONMENT.replace('/', '_')
    TARGET_HOST             = "${getHostByEnvironment(env.TARGET_ENVIRONMENT)}"

    ATHENA_DATABASE          = "${getAthenaDatabaseByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"
    ATHENA_OUTPUT_LOCATION   = "${getAthenaResultsBucketByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"
    ATHENA_TABLE             = "${getAthenaTableByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"
    ATHENA_LOGS_TYPE         = "${getAthenaLogsTypeByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"
    ATHENA_URL_FILTER_PREFIX = "${getAthenaUrlFilterPrefixByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"

    ATLAS_HOST          ="${getAtlasHostByEnvironment(env.TARGET_ENVIRONMENT)}"
    ATLAS_CLIENT_ID     ="${getAtlasClientIdByEnvironment(env.TARGET_ENVIRONMENT)}"
    ATLAS_CLIENT_SECRET ="${getAtlasClientSecretByEnvironment(env.TARGET_ENVIRONMENT)}"
    ATLAS_AUDIENCE      ="${getAtlasAudienceByEnvironment(env.TARGET_ENVIRONMENT)}"

    DD_API_KEY        = utility.getSecretValueById("infra/jenkins/apollo/common/datadog/DEVELOPMENT_API_KEY", "gdb-delphi-dev")
    DD_DASHBOARD_LINK = "https://app.datadoghq.com/dashboard/wgy-sq2-tba"

    CURRENT_DATE     = "${params.current_date}".trim()
    REPORT_FILE_NAME = "${env.TARGET_ENVIRONMENT_NAME}_report.html"

    SENTRY_DSN = utility.getSecretValueById("infra/jenkins/load-tester/SENTRY_DSN", "gdb-infra-dev")

    NOTIFICATIONS_CHANNEL = '#core-load-testing'
  }

  options {
    timeout(time: 180, unit: 'MINUTES')
    buildDiscarder logRotator(
      artifactDaysToKeepStr: '',
      artifactNumToKeepStr: '',
      daysToKeepStr: '',
      numToKeepStr: '30'
    )
    disableResume()
    disableConcurrentBuilds()
    ansiColor('xterm')
  }

  stages {
    stage('Build') {
      steps {
        script { currentBuild.description = "${env.ACCESS_LOGS_SOURCE_ENVIRONMENT} -> ${env.TARGET_ENVIRONMENT}" }
        sh label: 'docker login', script: 'make docker/login'
        sh label: 'docker build', script: """
          docker build \
            -t ${env.ECR_REGISTRY_URI}:core .
        """
      }
    }
    stage('Execute') {
      environment {
        AWS_PROFILE = "${getAwsProfileByEnvironment(params.ACCESS_LOGS_SOURCE_ENVIRONMENT)}"
        SAMPLE_FILE = "samples/${env.SOURCE_ENVIRONMENT_NAME}_${env.CURRENT_DATE}.csv"
      }
      steps {
        script {
          docker.image("${env.ECR_REGISTRY_URI}:core").inside("--ulimit nofile=90000:90000 -v /home/ec2-user/.aws:/home/locust/.aws") {
            sh label: 'prepare samples directory', script: 'mkdir -p samples/'
            def query_cmd = []
              query_cmd << 'python3'
              query_cmd << 'selectors/aws/athena.py'
              query_cmd << "-o ${env.SAMPLE_FILE}"
              query_cmd << "-d ${env.CURRENT_DATE}"
              if (params.EXTRA_ARGS != '') {
                query_cmd << "${params.EXTRA_ARGS}"
              }
            sh label: 'get samples from Athena', script: query_cmd.join(' ')
            sh label: 'check files', script: 'ls -ashil samples/'
            sh label: 'check content', script: "cat ${env.SAMPLE_FILE}"
            sh label: 'run performance tests', script: """
              locust \
                --locustfile locust/locustfile.py \
                --headless \
                -u ${params.NUM_USERS} \
                -r ${params.SPAWN_RATE} \
                -t ${params.RUN_TIME} \
                --csv report \
                --csv-full-history \
                --html ${env.REPORT_FILE_NAME} \
                --exit-code-on-error 0 \
                --host 'https://${env.TARGET_HOST}'
            """
          }
        }
      }
      post {
        always {
          sh 'ls -ashil'
          archiveArtifacts artifacts: env.REPORT_FILE_NAME, followSymlinks: false
          archiveArtifacts artifacts: '*.csv', followSymlinks: false
          archiveArtifacts artifacts: 'samples/*.csv', followSymlinks: false
          script {
            def csvFile = "${env.WORKSPACE}/report_stats.csv"
            def csvContent = readCSV(file: csvFile)

            if (csvContent != null && csvContent.size() > 0) {
              def lastRecord = csvContent.last()
              def messageRequestCount = lastRecord[2]
              def messageFailureCount = lastRecord[3]
              def messageAvgResponseTime = lastRecord[4]

              def slackMessage = """*Aggregated results for ${env.TARGET_ENVIRONMENT}:*\n\n*Request Count:* ${messageRequestCount} \n*Failure Count:* ${messageFailureCount} \n*Average Response Time:* ${messageAvgResponseTime}"""

              utility.slackNotify(currentBuild.currentResult, env.NOTIFICATIONS_CHANNEL, slackMessage)
            }
          }
        }
      }
    }
  }
}
