# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

---
# /*---------------------------------------------------------------------------8
# |                                                                            |
# |               This pipeline performs the software installation             |
# |              and must run on a self hosted deployment agent                |
# |                      due to long run time.                                 |
# |                                                                            |
# +------------------------------------4--------------------------------------*/

parameters:
  - name:                              sap_system_configuration_name
    displayName:                       "SAP System configuration name, use the following syntax: ENV-LOCA-VNET-SID"
    type:                              string
    default:                           DEV-WEEU-SAP01-X00

  - name:                              environment
    displayName:                       Workload Environment (DEV, QUA, PRD, ...)
    type:                              string
    default:                           DEV

  - name:                              sap_cal_product_name
    displayName:                       SAP CAL Product Name
    type:                              string

  - name:                              extra_params
    displayName:                       Extra Parameters
    type:                              string
    default:                           ""

  - name:                              base_os_configuration
    displayName:                       Core Operating System Configuration
    type:                              boolean
    default:                           true

  - name:                              sap_os_configuration
    displayName:                       SAP Operating System Configuration
    type:                              boolean
    default:                           true

  - name:                              sapcal_integration
    displayName:                       SAP CAL Integration
    type:                              boolean
    default:                           false

# 20220929 MKD - ACSS Registration <BEGIN>
  - name:                             acss_registration
    displayName:                      Register System in ACSS
    type:                             boolean
    default:                          true

  - name:                             acss_environment
    displayName:                      ACSS Prod/NonProd
    type:                             string
    values:
      - NonProd
      - Prod

  - name:                              acss_sap_product
    displayName:                       System Type
    type:                              string
    values:
      - S4HANA
      - ECC
      - Other
  # 20220929 MKD - ACSS Registration <END>

  - name:                              sap_automation_repo_path
    displayName:                       The local path on the agent where the sap_automation repo can be found
    type:                              string

  - name:                              config_repo_path
    displayName:                       The local path on the agent where the config repo can be found
    type:                              string

stages:
  - stage: Preparation_for_Ansible
    condition: and(not(failed()), not(canceled()))
    variables:
      - template:                      variables/07-sap-cal-installation-variables.yaml
        parameters:
          environment:                 ${{ parameters.environment }}
    displayName:                       OS Configuration and SAP Installation
    jobs:
      - job:                           Installation_step
        displayName:                   OS Configuration and SAP Installation
        timeoutInMinutes:              0
        workspace:
          clean:                       all
        steps:
          - template: templates\download.yaml
            parameters:
              getLatestFromBranch: true
          - task:                      PostBuildCleanup@4
          - bash: |
              #!/bin/bash
              # Exit immediately if a command exits with a non-zero status.
              set -e

              green="\e[1;32m" ; reset="\e[0m" ; boldred="\e[1;31m"
              if [[ ! -f /etc/profile.d/deploy_server.sh ]]; then
                echo -e "$green --- Install dos2unix ---$reset"
                  sudo apt-get -qq install dos2unix
              fi
              echo -e "$green--- Convert config file to UX format ---$reset"
              echo -e "$green--- Update .sap_deployment_automation/config as DEPLOYMENT_REPO_PATH can change on devops agent ---$reset"
                export HOME=${CONFIG_REPO_PATH}/$(Deployment_Configuration_Path)
                cd $HOME

              echo -e "$green--- Configure devops CLI extension ---$reset"
                az config set extension.use_dynamic_install=yes_without_prompt  --output none

                az extension add --name azure-devops --output none

                az devops configure --defaults organization=$(System.CollectionUri) project='$(System.TeamProject)' --output none

              echo -e "$green--- Validations ---$reset"
                ENVIRONMENT=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $1}' | xargs) ; echo Environment $ENVIRONMENT
                   LOCATION=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $2}' | xargs) ; echo Location    $LOCATION
                    NETWORK=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $3}' | xargs) ; echo Virtual network logical name $NETWORK
                        SID=$(echo ${SAP_SYSTEM_CONFIGURATION_NAME} | awk -F'-' '{print $4}' | xargs) ; echo SID $SID

                environment_file_name=$HOME/.sap_deployment_automation/$ENVIRONMENT$LOCATION$NETWORK ; echo configuration_file $environment_file_name
                          params_file=$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml              ;  echo sap_parameters_file $params_file

              if [ "azure pipelines" = "$(this_agent)" ]; then
                  echo "##vso[task.logissue type=error]Please use a self hosted agent for this playbook. Define it in the SDAF-${ENVIRONMENT} variable group using the 'POOL' variable."
                  exit 2
                fi

                if [ ! -f $environment_file_name ]; then
                  echo -e "$boldred--- $environment_file_name was not found ---$reset"
                  echo "##vso[task.logissue type=error]Workload zone configuration file $environment_file_name was not found."
                  exit 2
                fi

                if [ ! -f $params_file ]; then
                  echo -e "$boldred--- $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml was not found ---$reset"
                  echo "##vso[task.logissue type=error]File $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml was not found."
                  exit 2
                else
                  dos2unix -q $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/sap-parameters.yaml
                fi

                if [ ! -n ${SID} ]; then
                  echo "##vso[task.logissue type=error]SID was not found in ${SAP_SYSTEM_CONFIGURATION_NAME}."
                  exit 2
                fi

                if [ ! -f $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml ]; then
                  echo -e "$boldred--- $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml was not found ---$reset"
                  echo "##vso[task.logissue type=error]File $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml was not found."
                  exit 2
                fi
                dos2unix -q $HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}/${SID}_hosts.yaml

                export VARIABLE_GROUP_ID=$(az pipelines variable-group list --query "[?name=='$(variable_group)'].id | [0]")
                echo '$(variable_group) id: ' $VARIABLE_GROUP_ID
                if [ -z ${VARIABLE_GROUP_ID} ]; then
                    echo "##vso[task.logissue type=error]Variable group $(variable_group) could not be found."
                    exit 2
                fi

                echo "##vso[build.updatebuildnumber]Deploying ${SAP_SYSTEM_CONFIGURATION_NAME} using SAP CAL"

                echo "##vso[task.setvariable variable=SID;isOutput=true]${SID}"
                echo "##vso[task.setvariable variable=SAP_PARAMETERS;isOutput=true]sap-parameters.yaml"
                echo "##vso[task.setvariable variable=FOLDER;isOutput=true]$HOME/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}"
                echo "##vso[task.setvariable variable=HOSTS;isOutput=true]${SID}_hosts.yaml"

              echo -e "$green--- Get Files from the DevOps Repository ---$reset"
                cd ${CONFIG_REPO_PATH}/$(Deployment_Configuration_Path)/SYSTEM/${SAP_SYSTEM_CONFIGURATION_NAME}
                sap_params_updated=0

                fqdn="$(grep -m1 "$sap_fqdn:" sap-parameters.yaml | cut -d':' -f2-  | tr -d ' ' | tr -d '"')"
                if [ -z $fqdn ] ; then
                  sed -i 's|sap_fqdn:.*|sap_fqdn:                      '"$(sap_fqdn)"'|'  sap-parameters.yaml
                fi

                if [[ -n "${sapcalProductName}" ]]; then
                  echo -e "$green--- Add SAP CAL Product Name $sapcalProductName to sap-parameters.yaml ---$reset"
                  sed -i 's|sap_cal_product_name:.*|sap_cal_product_name:                    '"$sapcalProductName"'|'  sap-parameters.yaml
                fi

              echo -e "$green--- Get connection details ---$reset"
                mkdir -p artifacts

                az_var=$(az pipelines variable-group variable list --group-id ${VARIABLE_GROUP_ID} --query "${NETWORK}"Workload_Key_Vault.value --output tsv)
                if [ -z ${az_var} ]; then
                  export workload_key_vault=$(cat "${environment_file_name}"  | grep workloadkeyvault      | awk -F'=' '{print $2}' | xargs) ; echo 'Workload Key Vault' ${workload_key_vault}
                else
                  export workload_key_vault=${az_var} ; echo 'Workload Key Vault' ${workload_key_vault} ;
                fi

                az_var=$(az pipelines variable-group variable list --group-id ${VARIABLE_GROUP_ID} --query "${NETWORK}"Workload_Secret_Prefix.value  --output tsv)
                if [ -z ${az_var} ]; then
                  export workload_prefix=$(cat "${environment_file_name}"  | grep workload_zone_prefix      | awk -F'=' '{print $2}' | xargs) ; echo 'Workload Prefix' ${workload_prefix}
                else
                  export workload_prefix=${az_var} ; echo 'Workload Prefix' ${workload_prefix};
                fi

                az_var=$(az pipelines variable-group variable list --group-id ${VARIABLE_GROUP_ID} --query Terraform_Remote_Storage_Subscription.value  --output tsv)
                if [ -z ${az_var} ]; then
                  export control_plane_subscription=$(cat "${environment_file_name}"  | grep STATE_SUBSCRIPTION      | awk -F'=' '{print $2}' | xargs) ; echo 'Control Plane Subscription' ${control_plane_subscription}
                else
                  export control_plane_subscription=${az_var} ; echo 'Control Plane Subscription' ${control_plane_subscription}
                fi

                if [[ $EXTRA_PARAMETERS = "'$(EXTRA_PARAMETERS)'" ]]; then
                  new_parameters=$PIPELINE_EXTRA_PARAMETERS
                else
                  echo "##vso[task.logissue type=warning]Extra parameters were provided - '$EXTRA_PARAMETERS'"
                  new_parameters="$EXTRA_PARAMETERS $PIPELINE_EXTRA_PARAMETERS"
                fi

                echo "##vso[task.setvariable variable=SSH_KEY_NAME;isOutput=true]${workload_prefix}-sid-sshkey"
                echo "##vso[task.setvariable variable=VAULT_NAME;isOutput=true]$workload_key_vault"
                echo "##vso[task.setvariable variable=PASSWORD_KEY_NAME;isOutput=true]${workload_prefix}-sid-password"
                echo "##vso[task.setvariable variable=USERNAME_KEY_NAME;isOutput=true]${workload_prefix}-sid-username"
                echo "##vso[task.setvariable variable=NEW_PARAMETERS;isOutput=true]${new_parameters}"
                echo "##vso[task.setvariable variable=CP_SUBSCRIPTION;isOutput=true]${control_plane_subscription}"


              echo -e "$green--- az login ---$reset"
                # If the deployer_file exists we run on a deployer configured by the framework instead of a azdo hosted one
                deployer_file=/etc/profile.d/deploy_server.sh
                if [ "$USE_MSI" = "true" ]; then
                  echo  "Using MSI"
                  source /etc/profile.d/deploy_server.sh
                  az account set --subscription $control_plane_subscription

                else
                  if [ ! -n $AZURE_CLIENT_ID ]; then
                    echo "##vso[task.logissue type=error]Variable ARM_CLIENT_ID was not defined."
                    exit 2
                  fi

                  if [ ! -n $AZURE_CLIENT_SECRET ]; then
                    echo "##vso[task.logissue type=error]Variable ARM_CLIENT_SECRET was not defined."
                    exit 2
                  fi

                  if [ ! -n $AZURE_TENANT_ID ]; then
                    echo "##vso[task.logissue type=error]Variable ARM_TENANT_ID was not defined."
                    exit 2
                  fi
                  az login --service-principal --username $AZURE_CLIENT_ID --password=${AZURE_CLIENT_SECRET} --tenant $AZURE_TENANT_ID --output none
                  return_code=$?
                  if [ 0 != $return_code ]; then
                    echo -e "$boldred--- Login failed ---$reset"
                    echo "##vso[task.logissue type=error]az login failed."
                    exit $return_code
                  fi
                  az account set --subscription $control_plane_subscription
                fi

                return_code=$?
                if [ 0 != $return_code ]; then
                  echo -e "$boldred--- Login failed ---$reset"
                  echo "##vso[task.logissue type=error]az login failed."
                  exit $return_code
                fi

                az_var=$(az pipelines variable-group variable list --group-id ${VARIABLE_GROUP_ID} --query "Deployer_Key_Vault.value" | tr -d \")
                if [ -n ${az_var} ]; then
                    kv_name=${az_var}; echo "Key Vault="$kv_name
                else
                    kv_name=$(cat .sap_deployment_automation/$(environment_code)$(location_code) | grep keyvault |awk -F'=' '{print $2}'); echo "Key Vault="$kv_name
                fi

                echo "##vso[task.setvariable variable=KV_NAME;isOutput=true]$kv_name"

                if [ "your S User" == "${SUsername}" ]; then
                  echo "##vso[task.logissue type=error]Please define the S-Username variable."
                  exit 2
                fi

                if [ "your S user password" == "${SPassword}" ]; then
                  echo "##vso[task.logissue type=error]Please define the S-Password variable."
                  exit 2
                fi

              echo -e "$green--- Set S-Username and S-Password in the key_vault if not yet there ---$reset"

                export SUsernamefromVault=$(az keyvault secret list --vault-name "${kv_name}" --subscription "${ARM_SUBSCRIPTION_ID}" --query "[].{Name:name} | [? contains(Name,'S-Username')] | [0]"  -o tsv)
                if [ $SUsernamefromVault == $SUsername ]; then
                  echo -e "$green--- $SUsername present in keyvault. In case of download errors check that user and password are correct ---$reset"
                  echo "##vso[task.setvariable variable=SUSERNAME;isOutput=true]$SUsernamefromVault"
                else
                  echo -e "$green--- Setting the S username in key vault ---$reset"
                  az keyvault secret set --name "S-Username" --vault-name $kv_name --value="${SUsername}" --subscription "${ARM_SUBSCRIPTION_ID}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --output none
                  echo "##vso[task.setvariable variable=SUSERNAME;isOutput=true]$SUsername"
                fi

                export SPasswordfromVault=$(az keyvault secret list --vault-name "${kv_name}" --subscription "${ARM_SUBSCRIPTION_ID}" --query "[].{Name:name} | [? contains(Name,'S-Password')] | [0]"  -o tsv)
                if [ ${SPassword} == $SPasswordfromVault ]; then
                  echo "##vso[task.setvariable variable=SPASSWORD;isOutput=true]${SPasswordfromVault}"
                  echo -e "$green--- Password present in keyvault. In case of download errors check that user and password are correct ---$reset"
                else
                  echo -e "$green--- Setting the S user name password in key vault ---$reset"
                  az keyvault secret set --name "S-Password" --vault-name $kv_name --value "${SPassword}" --subscription "${ARM_SUBSCRIPTION_ID}" --expires "$(date -d '+1 year' -u +%Y-%m-%dT%H:%M:%SZ)" --output none
                  echo "##vso[task.setvariable variable=SPASSWORD;isOutput=true]${SPassword}"
                fi

                az keyvault secret show --name ${workload_prefix}-sid-sshkey --vault-name $workload_key_vault --subscription $AZURE_SUBSCRIPTION_ID --query value -o tsv > artifacts/${SAP_SYSTEM_CONFIGURATION_NAME}_sshkey
                cp sap-parameters.yaml artifacts/.
                cp ${SID}_hosts.yaml artifacts/.

                2> >(while read line; do (>&2 echo "STDERROR: $line"); done)
            name:                            Preparation
            displayName:                     Preparation for Ansible
            env:
              SCRIPT_PATH:                   $${{ parameters.sap_automation_repo_path }}/deploy/pipelines/templates/*.sh
              SYSTEM_ACCESSTOKEN:            $(System.AccessToken)
              AZURE_DEVOPS_EXT_PAT:          $(System.AccessToken)
              ANSIBLE_HOST_KEY_CHECKING:     false
              AZURE_CLIENT_ID:               $(ARM_CLIENT_ID)
              AZURE_CLIENT_SECRET:           $(ARM_CLIENT_SECRET)
              AZURE_TENANT_ID:               $(ARM_TENANT_ID)
              AZURE_SUBSCRIPTION_ID:         $(Terraform_Remote_Storage_Subscription)
              ANSIBLE_COLLECTIONS_PATH:      /opt/ansible/collections
              CONFIG_REPO_PATH:              ${{ parameters.config_repo_path }}
              SAP_SYSTEM_CONFIGURATION_NAME: ${{ parameters.sap_system_configuration_name }}
              EXTRA_PARAMETERS:              $(EXTRA_PARAMETERS)
              PIPELINE_EXTRA_PARAMETERS:     ${{ parameters.extra_params }}
              USE_MSI:                       $(USE_MSI)
              SUsername:                     $(S-Username)
              SPassword:                     $(S-Password)
              sapcalProductName:             ${{ parameters.sap_cal_product_name }}

          - template:                        templates\run-ansible.yaml
            parameters:
              displayName:                   "Parameter validation"
              ansibleFilePath:               ${{ parameters.sap_automation_repo_path }}/deploy/ansible/playbook_00_validate_parameters.yaml
              secretName:                    "$(Preparation.SSH_KEY_NAME)"
              passwordSecretName:            "$(Preparation.PASSWORD_KEY_NAME)"
              userNameSecretName:            "$(Preparation.USERNAME_KEY_NAME)"
              vaultName:                     $(Preparation.VAULT_NAME)
              parametersFolder:              $(Preparation.FOLDER)
              sapParams:                     "${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path)/SYSTEM/${{ parameters.sap_system_configuration_name }}/artifacts/$(Preparation.SAP_PARAMETERS)"
              sidHosts:                      $(Preparation.HOSTS)
              extraParams:                   "$(Preparation.NEW_PARAMETERS)"
              azureClientId:                 $(ARM_CLIENT_ID)
              azureClientSecret:             $(ARM_CLIENT_SECRET)
              azureTenantId:                 $(ARM_TENANT_ID)
              azureSubscriptionId:           $(ARM_SUBSCRIPTION_ID)
              USE_MSI:                       $(USE_MSI)
          - ${{ if eq(parameters.base_os_configuration, true) }}:
              - template:                    templates\run-ansible.yaml
                parameters:
                  displayName:               "Operating System Configuration"
                  ansibleFilePath:           ${{ parameters.sap_automation_repo_path }}/deploy/ansible/playbook_01_os_base_config.yaml
                  secretName:                "$(Preparation.SSH_KEY_NAME)"
                  passwordSecretName:        "$(Preparation.PASSWORD_KEY_NAME)"
                  userNameSecretName:        "$(Preparation.USERNAME_KEY_NAME)"
                  vaultName:                 $(Preparation.VAULT_NAME)
                  parametersFolder:          $(Preparation.FOLDER)
                  sapParams:                 "${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path)/SYSTEM/${{ parameters.sap_system_configuration_name }}/artifacts/$(Preparation.SAP_PARAMETERS)"
                  sidHosts:                  $(Preparation.HOSTS)
                  extraParams:               "$(Preparation.NEW_PARAMETERS)"
                  azureClientId:             $(ARM_CLIENT_ID)
                  azureClientSecret:         $(ARM_CLIENT_SECRET)
                  azureTenantId:             $(ARM_TENANT_ID)
                  azureSubscriptionId:       $(ARM_SUBSCRIPTION_ID)
                  USE_MSI:                   $(USE_MSI)
          - ${{ if eq(parameters.sap_os_configuration, true) }}:
              - template:                    templates\run-ansible.yaml
                parameters:
                  displayName:               "SAP Specific Operating System Configuration"
                  ansibleFilePath:           ${{ parameters.sap_automation_repo_path }}/deploy/ansible/playbook_02_os_sap_specific_config.yaml
                  secretName:                "$(Preparation.SSH_KEY_NAME)"
                  passwordSecretName:        "$(Preparation.PASSWORD_KEY_NAME)"
                  userNameSecretName:        "$(Preparation.USERNAME_KEY_NAME)"
                  vaultName:                 $(Preparation.VAULT_NAME)
                  parametersFolder:          $(Preparation.FOLDER)
                  sapParams:                 "${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path)/SYSTEM/${{ parameters.sap_system_configuration_name }}/artifacts/$(Preparation.SAP_PARAMETERS)"
                  sidHosts:                  $(Preparation.HOSTS)
                  extraParams:               "$(Preparation.NEW_PARAMETERS)"
                  azureClientId:             $(ARM_CLIENT_ID)
                  azureClientSecret:         $(ARM_CLIENT_SECRET)
                  azureTenantId:             $(ARM_TENANT_ID)
                  azureSubscriptionId:       $(ARM_SUBSCRIPTION_ID)
                  USE_MSI:                   $(USE_MSI)
          - ${{ if eq(parameters.sapcal_integration, true) }}:
              - template:                    templates\run-ansible.yaml
                parameters:
                  displayName:               "SAPCAL Integration"
                  ansibleFilePath:           ${{ parameters.sap_automation_repo_path }}/deploy/ansible/playbook_sapcal_integration.yaml
                  secretName:                "$(Preparation.SSH_KEY_NAME)"
                  passwordSecretName:        "$(Preparation.PASSWORD_KEY_NAME)"
                  userNameSecretName:        "$(Preparation.USERNAME_KEY_NAME)"
                  vaultName:                 $(Preparation.VAULT_NAME)
                  parametersFolder:          $(Preparation.FOLDER)
                  sapParams:                 "${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path)/SYSTEM/${{ parameters.sap_system_configuration_name }}/artifacts/$(Preparation.SAP_PARAMETERS)"
                  sidHosts:                  $(Preparation.HOSTS)
                  extraParams:               "$(Preparation.NEW_PARAMETERS)"
                  azureClientId:             $(ARM_CLIENT_ID)
                  azureClientSecret:         $(ARM_CLIENT_SECRET)
                  azureTenantId:             $(ARM_TENANT_ID)
                  azureSubscriptionId:       $(ARM_SUBSCRIPTION_ID)
                  sapcalProductName:         ${{ parameters.sap_cal_product_name }}
                  USE_MSI:                   $(USE_MSI)
          - template:                        templates\collect-calapi-file.yaml
            parameters:
              filePath:                      ${{ parameters.config_repo_path }}/$(Deployment_Configuration_Path)/SYSTEM/${{ parameters.sap_system_configuration_name }}
