def ENAMES = [ 'prod-open', 'prod' ]
//def def ENAMES = [ 'dev-open', 'dev' ]
def REPOS = ['prod': 'ssh://git@git.sdsys.ru:8022/labportal/stack-deploy.git',
             'prod-open': 'ssh://git@git.sdsys.ru:8022/labportal/stack-deploy-open.git']
def GIT_DIR = ['prod': 'stack-deploy', 'prod-open': 'stack-deploy-open']
def CLUSTERS = ['prod': 'iru-swarm.infoclinica.lan',
                'prod-open': 'iru-swarm1-open.infoclinica.ru',
                'dev': 'dev-iru-swarm.infoclinica.lan',
                'dev-open': 'dev-iru-swarm1-open.infoclinica.lan']
def REGISTRIES = ['prod': 'registry.infoclinica.ru:5000',
                  'prod-open': 'registry.infoclinica.ru:5000',
                  'dev': 'dev-registry.infoclinica.ru:5000',
                  'dev-open': 'dev-registry.infoclinica.ru:5000']
def DHOST = ['prod': 'tcp://iru-swarm.infoclinica.lan:2376',
             'prod-open': 'tcp://iru-swarm1-open.infoclinica.ru:2376',
             'dev': 'tcp://dev-iru-swarm.infoclinica.lan:2376',
             'dev-open': 'tcp://dev-iru-swarm1-open.infoclinica.lan:2376']

def LIST_SERVICE = [:]
def TO_ROLLBACK = [:]
def ERROR_JOB
def VERSION_TO_UPDATE

pipeline {
  agent {
    label "swarm"
  }
  environment {
    JENKINS_MAIL='jenkins.dev@sdsys.ru'
    DOCKER_CERT_PATH='/run/secrets/swarm'
    DOCKER_IMAGE='analis-wineservice'
    SERVICE_LABEL='analis-std'
    STACK_LABEL='analis-wineservice'
  }
  parameters {
    string(
      name: "mailto",
      defaultValue: "admin@sdsys.ru",
      description: "Email which has to be notified."
    )
    choice (
      choices: 'up\ndown',
      description: 'What you want? Up version or down?',
      name: 'TASK_ACTION'
    )
  }
  stages {
    stage("Git Pull. Define Version to Update") {
      steps {
        script {
          ENAMES.each { item ->
            withCredentials([sshUserPrivateKey(credentialsId: 'provision', keyFileVariable: 'GIT_SSH_KEY', passphraseVariable: '', usernameVariable: 'GIT_SSH_USERNAME')]) {
              sh """set +x && GIT_SSH_COMMAND='ssh -i ${GIT_SSH_KEY} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
                    git clone ${REPOS.get((item))}
                 """
            }
          }
          switch (TASK_ACTION) {
            case 'up':
              ENAMES.each { item ->
                VERSION_TO_UPDATE = sh (script: "set +x && cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.build-version" , returnStdout: true).trim()
              }
              sh "set +x && echo \"Update version of Apps to $VERSION_TO_UPDATE\" > commit.txt"
              break
            case 'down':
              ENAMES.each { item ->
                VERSION_TO_UPDATE = sh (script: "set +x && cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.old-stable-version" , returnStdout: true).trim()
              }
              sh "set +x && echo \"Downgrade version of Apps to $VERSION_TO_UPDATE\" > commit.txt"
              break
          }
        }
      }
    }
    stage("Get Names Of Running Services") {
      steps {
        script {
          ENAMES.each { item ->
            echo "Viewing: ${item} services, on ${CLUSTERS.get((item))}"
            LIST_SERVICE[item] = sh (script: "set +x && DOCKER_HOST=${DHOST.get((item))} DOCKER_TLS_VERIFY=1 docker service ls -f \
              label=com.docker.stack.namespace=$STACK_LABEL -f \
              label=ru.infoclinica.service=$SERVICE_LABEL --format '{{.Name}}'" , returnStdout: true).split('\n')
            switch (TASK_ACTION) {
              case 'up':
                echo "These services will be updated to version $VERSION_TO_UPDATE: ${LIST_SERVICE.get(item)}"
                break
              case 'down':
                echo "These services will be downgraded to version $VERSION_TO_UPDATE ${LIST_SERVICE.get(item)}"
                break
            }
          }
        }
      }
    }
    stage("Update Services") {
      steps {
        script {
          ENAMES.each { item ->
            TO_ROLLBACK[item] = []
            try {
              for (name in LIST_SERVICE.get(item)) {
                TO_ROLLBACK[item].add(name)
                echo "Update service $name"
                sh "set +x && DOCKER_HOST=${DHOST.get((item))} DOCKER_TLS_VERIFY=1 docker service update \
                    $name --image ${REGISTRIES.get((item))}/lab/$DOCKER_IMAGE:$VERSION_TO_UPDATE"
              }
            }
            catch (err) {
              def STABLE_VERSION = sh (script: "set +x && cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.stable-version" , returnStdout: true).trim()
              TO_ROLLBACK.each { target, value ->
                for (service_name in value) {
                  echo "Recoverig $service_name running in $target to $STABLE_VERSION"
                  sh "set +x && DOCKER_HOST=${DHOST.get((item))} DOCKER_TLS_VERIFY=1 docker service rollback $service_name"
                }
              }
              ERROR_JOB = TO_ROLLBACK[item][-1]
              currentBuild.result = 'FAILURE'
              error ("Failure on update $ERROR_JOB. The service(s) $ERROR_JOB was rollback!")
            }
          }
        }
      }
    }
    stage("Update Tags") {
      steps {
        script {
          ENAMES.each { item ->
            def STABLE_VERSION = sh (script: "set +x && cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.stable-version" , returnStdout: true).trim()
            def OLD_STABLE_VERSION = sh (script: "set +x && cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.old-stable-version" , returnStdout: true).trim()
            sh "set +x && echo $STABLE_VERSION > ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.old-stable-version"
            sh "set +x && echo $VERSION_TO_UPDATE > ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.stable-version" 
          }
        }
      }
    }
    stage("Push New Versions To Git") {
      steps {
        script {
          sh "cat commit.txt"
          ENAMES.each { item ->
            sh "cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.stable-version"
            sh "cat ${GIT_DIR.get((item))}/tags/lab/analis-wineservice.old-stable-version"
            withCredentials([sshUserPrivateKey(credentialsId: 'provision', keyFileVariable: 'GIT_SSH_KEY', passphraseVariable: '', usernameVariable: 'GIT_SSH_USERNAME')]) {
              sh """cd ${GIT_DIR.get((item))}
                    git add -A
                    git config --global user.email "${JENKINS_MAIL}"
                    git config --global user.name "Jenkins"
                    git commit -F ../commit.txt
                    GIT_SSH_COMMAND='ssh -i ${GIT_SSH_KEY} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
                    git push origin master
                 """
            }
          }
        }
      }
    }
  }
  post {
    always {
      echo "CleaningUp work directory"
      deleteDir()
    }
    failure {
      mail charset: 'UTF-8',
           subject: "Jenkins build ERROR",
           mimeType: 'text/html',
           to: "${mailto}",
           body: "<b>ATTENTION!!!</b> <br> <b>Failure update:</b> $ERROR_JOB <br><b>Was rollback:</b> $TO_ROLLBACK <b><br>Project Name:</b> ${env.JOB_NAME} <b><br>Build Number:</b> ${env.BUILD_NUMBER} <b><br>URL Build:</b> ${RUN_DISPLAY_URL}"
    }
  }
}