import hudson.model.Node.Mode
import hudson.slaves.*
import jenkins.model.Jenkins
import hudson.plugins.sshslaves.SSHLauncher

library changelog: false, identifier: 'lib@master', retriever: modernSCM([
    $class: 'GitSCMSource',
    remote: 'https://github.com/Percona-Lab/jenkins-pipelines.git'
]) _

void runStaging(String DOCKER_VERSION, CLIENT_VERSION, CLIENTS, PMM_QA_GIT_BRANCH, PMM_QA_GIT_COMMIT_HASH) {
    stagingJob = build job: 'aws-staging-start', parameters: [
        string(name: 'DOCKER_VERSION', value: DOCKER_VERSION),
        string(name: 'CLIENT_VERSION', value: CLIENT_VERSION),
        string(name: 'CLIENTS', value: ''),
        string(name: 'NOTIFY', value: 'false'),
        string(name: 'DAYS', value: '1'),
        string(name: 'PMM_QA_GIT_BRANCH', value: PMM_QA_GIT_BRANCH),
        string(name: 'PMM_QA_GIT_COMMIT_HASH', value: PMM_QA_GIT_COMMIT_HASH)
    ]
    env.VM_IP = stagingJob.buildVariables.IP
    env.VM_NAME = stagingJob.buildVariables.VM_NAME
    env.ADMIN_PASSWORD = "admin"
    env.PMM_URL = "http://admin:${ADMIN_PASSWORD}@${VM_IP}"
}

void destroyStaging(IP) {
    build job: 'aws-staging-stop', parameters: [
        string(name: 'VM', value: IP),
    ]
}

void runTAP(String TYPE, String PRODUCT, String COUNT, String VERSION) {
    node(env.VM_NAME){
        withCredentials([aws(accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AMI/OVF', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY')]) {
            sh """
                set -o errexit
                set -o xtrace

                aws ecr-public get-login-password --region us-east-1 | docker login -u AWS --password-stdin public.ecr.aws/e7j3v3n0

                test -f /usr/lib64/libsasl2.so.2 || sudo ln -s /usr/lib64/libsasl2.so.3.0.0 /usr/lib64/libsasl2.so.2
                export PATH=$PATH:/usr/sbin
                export instance_t="${TYPE}"
                export instance_c="${COUNT}"
                export version="${VERSION}"
                export pmm_server_ip=${VM_IP}
                export stress="1"
                export table_c="100"
                export tap="1"
                export PMM_VERSION=${PMM_VERSION}

                sudo chmod 755 /srv/pmm-qa/pmm-tests/pmm-framework.sh

                # This export is used by pmm-framework
                export CLIENT_VERSION=${CLIENT_VERSION}

                if [[ ${CLIENT_VERSION} == http* ]]; then
                    export PATH="/home/ec2-user/workspace/aws-staging-start/pmm2-client/bin:$PATH"
                fi

                bash /srv/pmm-qa/pmm-tests/pmm-2-0-bats-tests/pmm-testsuite.sh | tee /tmp/result.tap
            """
        }
    }
    withCredentials([sshUserPrivateKey(credentialsId: 'aws-jenkins', keyFileVariable: 'KEY_PATH', passphraseVariable: '', usernameVariable: 'USER')]) {
        sh '''
            scp -i "${KEY_PATH}" -o ConnectTimeout=1 -o StrictHostKeyChecking=no \
                ${USER}@${VM_IP}:/tmp/result.tap \
                ${TYPE}_${VERSION}.tap
            cat ${TYPE}_${VERSION}.tap \
                | ./node_modules/tap-junit/bin/tap-junit \
                    --name ${TYPE}_${VERSION}.xml \
                    --output ./ \
                    --pretty \
                    || :
        '''
    }
}

void runPlaywrightTests() {
    node(env.VM_NAME){
        git poll: false, branch: PMM_UI_GIT_BRANCH, url: 'https://github.com/percona/pmm-ui-tests.git'

        withCredentials([aws(accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AMI/OVF', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY')]) {
            sh '''
                set -ex
                node -e "console.log('Running Node.js ' + process.version)"

                cd cli
                npm install
                npx playwright install

                if [[ ${CLIENT_VERSION} == http* ]]; then
                    export PATH="/home/ec2-user/workspace/aws-staging-start/pmm2-client/bin:$PATH"
                fi

                set +e
                npx playwright test
            '''
        }
    }
}

void fetchAgentLog(String CLIENT_VERSION) {
    withCredentials([sshUserPrivateKey(credentialsId: 'aws-jenkins', keyFileVariable: 'KEY_PATH', passphraseVariable: '', usernameVariable: 'USER')]) {
        sh '''
            ssh -i "${KEY_PATH}" -o ConnectTimeout=1 -o StrictHostKeyChecking=no ${USER}@${VM_IP} "
                set -o errexit
                set -o xtrace
                if [[ "\${CLIENT_VERSION}" != http* ]]; then
                    journalctl -u pmm-agent.service > pmm-agent.log
                fi
            "

            if [[ ${CLIENT_VERSION} != http* ]]; then
                scp -i "${KEY_PATH}" -o ConnectTimeout=1 -o StrictHostKeyChecking=no \
                    ${USER}@${VM_IP}:pmm-agent.log \
                    pmm-agent.log
            fi

            if [[ ${CLIENT_VERSION} == http* ]]; then
                scp -i "${KEY_PATH}" -o ConnectTimeout=1 -o StrictHostKeyChecking=no \
                    ${USER}@${VM_IP}:workspace/aws-staging-start/pmm-agent.log \
                    pmm-agent.log
            fi
        '''
    }
}

def latestVersion = pmmVersion()

pipeline {
    agent {
        label 'agent-amd64-ol9'
    }
    parameters {
        string(
            defaultValue: 'perconalab/pmm-server:dev-latest',
            description: 'PMM Server docker container version (image-name:version-tag)',
            name: 'DOCKER_VERSION')
        string(
            defaultValue: 'dev-latest',
            description: 'PMM Client version',
            name: 'CLIENT_VERSION')
        string(
            defaultValue: 'perconalab/pmm-client:dev-latest',
            description: 'PMM Client Docker tag',
            name: 'CLIENT_DOCKER_VERSION')
        string(
            defaultValue: 'main',
            description: 'Tag/Branch for pmm-qa repository',
            name: 'PMM_QA_GIT_BRANCH')
        string(
            defaultValue: '',
            description: 'Commit hash for pmm-qa branch',
            name: 'PMM_QA_GIT_COMMIT_HASH')
        string(
                defaultValue: 'main',
                description: 'Tag/Branch for pmm-ui repository',
                name: 'PMM_UI_GIT_BRANCH')
        string(
            defaultValue: latestVersion,
            description: 'pmm2-client latest version',
            name: 'PMM_VERSION')
    }
    options {
        skipDefaultCheckout()
    }
    stages {
        stage('Prepare') {
            steps {
                sh '''
                    npm install tap-junit
                '''
            }
        }
        stage('Start staging') {
            steps {
                runStaging(DOCKER_VERSION, CLIENT_VERSION, '--addclient=ps,1 --pmm2', PMM_QA_GIT_BRANCH, PMM_QA_GIT_COMMIT_HASH)
                script {

                    SSHLauncher ssh_connection = new SSHLauncher(env.VM_IP, 22, 'aws-jenkins')
                    DumbSlave node = new DumbSlave(env.VM_NAME, "spot instance job", "/home/ec2-user/", "1", Mode.EXCLUSIVE, "", ssh_connection, RetentionStrategy.INSTANCE)

                    Jenkins.instance.addNode(node)
                }
            }
        }
        stage('Sanity check') {
            steps {
                sh 'timeout 100 bash -c \'while [[ "$(curl -s -o /dev/null -w \'\'%{http_code}\'\' \${PMM_URL}/ping)" != "200" ]]; do sleep 5; done\' || false'
            }
        }
        stage('Test: CLI Playwright') {
            steps {
                runPlaywrightTests()
            }
        }
        stage('Test: MDB_4_2') {
            steps {
                runTAP("modb", "modb", "3", "4.2")
            }
        }
        stage('Test: MDB_4_0') {
            steps {
                runTAP("modb", "modb", "3", "4.0")
            }
        }
        stage('Test: PSMDB_4_0') {
            steps {
                runTAP("mo", "psmdb", "3", "4.0")
            }
        }
        stage('Check Results') {
            steps {
                script {
                    OK = sh (
                        script: 'grep "^ok" *.tap | grep -v "# skip" | wc -l',
                        returnStdout: true
                    ).trim()
                    SKIP = sh (
                        script: 'grep "# skip" *.tap | wc -l',
                        returnStdout: true
                    ).trim()
                    FAIL = sh (
                        script: 'grep "^not ok" *.tap | wc -l',
                        returnStdout: true
                    ).trim()
                    if (FAIL.toInteger() > 0) {
                        sh "exit 1"
                    }
                }
            }
        }
    }
    post {
        always {
            sh '''
                curl --insecure ${PMM_URL}/logs.zip --output logs.zip || true
            '''
            fetchAgentLog(CLIENT_VERSION)
            script {
                junit allowEmptyResults: true, testResults: '**/*.xml'
            }
            script {
                if(env.VM_NAME) {
                    destroyStaging(VM_NAME)
                    archiveArtifacts artifacts: 'logs.zip'
                    archiveArtifacts artifacts: 'pmm-agent.log'
                }
                def node = Jenkins.instance.getNode(env.VM_NAME)
                Jenkins.instance.removeNode(node)
            }
        }
    }
}
