Commit 2d4bfd82 authored by Pascal Déchamboux's avatar Pascal Déchamboux
Browse files

Validate extension for managing CF services

parent e882e779
Loading
Loading
Loading
Loading
+181 −18
Original line number Diff line number Diff line
@@ -36,8 +36,15 @@ workflow:
    - when: always

variables:
  # Color code for traces
  COLOR_GREEN: "\e[1;32m"
  COLOR_RED: "\e[1;31m"
  COLOR_BLUE: "\e[1;34m"
  COLOR_NONE: "\e[0m"
  COLOR_YELLOW: "\e[1;33m"
  
  # variabilized tracking image
  TBC_TRACKING_IMAGE: "registry.gitlab.com/to-be-continuous/tools/tracking:master"
  TBC_TRACKING_IMAGE: "$CI_REGISTRY/to-be-continuous/tools/tracking:master"

  # Docker Image with CF CLI tool (can be overridden)
  CF_CLI_IMAGE: "registry.hub.docker.com/governmentpaas/cf-cli"
@@ -473,15 +480,6 @@ stages:
      appname="$6"
    fi

    # find manifest
    manifestfile=$(ls -1 "$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}-${env}.yml" 2>/dev/null || ls -1 "$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}.yml" 2>/dev/null || echo "")
    if [[ -z "$manifestfile" ]]
    then
      log_error "Manifest not found, lookedup paths are:\n - \\e[33;1m$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}-${env}.yml\\e[0m\n - \\e[33;1m$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}.yml\\e[0m"
      exit 1
    fi
    export manifestfile

    log_info "--- \\e[32mdeploy\\e[0m (env: \\e[33;1m${env}\\e[0m)"
    log_info "--- looking for CF scripts in directory: \\e[33;1m${CF_SCRIPTS_DIR}\\e[0m"

@@ -491,7 +489,14 @@ stages:
    export targetvarfile="$CF_SCRIPTS_DIR/generated-vars.yml"
    generate_vars_file

    # find manifest
    export manifestfile=$(ls -1 "$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}-${env}.yml" 2>/dev/null || ls -1 "$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}.yml" 2>/dev/null || echo "")
    if [[ -z "$manifestfile" ]]
    then
      log_info "Manifest not found, lookedup paths are:\n - \\e[33;1m$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}-${env}.yml\\e[0m\n - \\e[33;1m$CF_SCRIPTS_DIR/${CF_MANIFEST_BASENAME}.yml\\e[0m\n - no app to deploy"
    else
      push_application
    fi

    check_readiness

@@ -664,8 +669,13 @@ stages:
    pre_delete

    # delete app
    local sfound=$(cf apps | sed -e 1,3d | grep "^${appname} " | cat)
    if [[ -z "$sfound" ]]; then
      log_info "--- nothing to delete"
    else
      log_info "--- \\e[32mcf delete\\e[0m"
      cf delete "$appname" -f -r
    fi

    post_delete
  }
@@ -744,6 +754,156 @@ stages:
    done
  }

  function get_desc_field() {
    local field_value=$(cat ${CF_SCRIPTS_DIR}/$1 | jq .${2})
    local notnull=$3
    export desc_field_error=""
    if [[ "${field_value}" == "null" ]]; then
      if [[ "${notnull}" == "true" ]]; then
   	    export desc_field_error="${2} should not be null: creation aborted"
   	    return
   	  else
   	    export desc_field=""
   	  fi
    else
      if [[ "${field_value}" == "\""* ]]; then
        export desc_field=$(expr substr ${field_value} 2 $(( ${#field_value} - 2 )))
      else
        export desc_field=${field_value}
      fi
    fi
  }

  function is_cups() {
    export res_is_cups
    if [[ "$1" = "cups" && "$2" = "cups" ]]; then
      res_is_cups="CUPS"
      return
    fi
    if [[ "$1" = "CUPS" && "$2" != "CUPS" ]]; then
      res_is_cups="CUPS"
      return
    fi
    if [[ "$1" = "cups" && "$2" != "CUPS" ]]; then
      res_is_cups="CUPS"
      return
    fi
    if [[ "$1" = "CUPS" && "$2" = "cups" ]]; then
      res_is_cups="CUPS"
      return
    fi
    res_is_cups="SERV"
  }

  function create_service() {
    local fields=("cfServiceName" "cfServiceOffering" "cfServicePlan" "cfServiceBroker" "cfServiceArgs")
    local mandatory=("true" "true" "true" "false" "false")
    local fvalues=("" "" "" "" "")
    local service_desc=$1
    local smsg="Create service instance ${COLOR_YELLOW}${service_desc}${COLOR_NONE}: "
    for fi in ${!fields[@]}
    do
      get_desc_field $service_desc "${fields[$fi]}" "${mandatory[$fi]}"
      if [[ ! -z "$desc_field_error" ]]; then
        log_info "${smsg}${COLOR_RED}KO - skipped${COLOR_NONE} (${COLOR_BLUE}${desc_field_error}${COLOR_NONE})"
        manage_services_errors=$((manage_services_errors+1))
        return
      fi
      fvalues[$fi]=$(echo ${desc_field} | tr -d '\r' | envsubst)
    done
    log_info "${smsg}service definition OK - proceed"
    for fi in ${!fields[@]}
    do
      log_info "--- ${fields[$fi]}: ${COLOR_YELLOW}${fvalues[$fi]}${COLOR_NONE}"
    done
    local sfound=$(cf services | sed -e 1,3d | grep "^${fvalues[0]}" | cat)
    if [[ -z "$sfound" ]]; then
      is_cups "${fvalues[1]}" "${fvalues[2]}"
      if [[ "$res_is_cups" = "CUPS" ]]; then
        cf cups ${fvalues[0]} -p $(echo "'${fvalues[4]}'" | tr -d ' ') >/dev/null 2>&1
      else
         if [[ -z "${fvalues[3]}" ]]; then
          broker=""
        else
          broker="-b ${fvalues[3]}"
        fi
        local argfile=`mktemp`
        if [[ -z "${fvalues[4]}" ]]; then
          params=""
        else
          echo ${fvalues[4]} >${argfile}
          params="-c ${argfile}"
        fi
         cf create-service ${fvalues[1]} ${fvalues[2]} ${fvalues[0]} ${broker} ${params} -w >/dev/null 2>&1
        rm -f ${argfile}
      fi
      log_info "${COLOR_GREEN}... created${COLOR_NONE}"
    else
      log_info "${COLOR_BLUE}... service instance \"${fvalues[0]}\" already exist - skipped${COLOR_NONE}"
    fi
  }

  function delete_service() {
    case ${ENV_TYPE} in
    staging | production)
      log_info "Delete service instance ${COLOR_YELLOW}${service_desc}${COLOR_NONE}: ignored (env=${ENV_TYPE})"
      ;;
    *)
      local service_desc=$1
      smsg="Delete service instance ${COLOR_YELLOW}${service_desc}${COLOR_NONE}: "
      get_desc_field $service_desc "cfServiceName" "true"
      if [[ ! -z "$desc_field_error" ]]; then
        log_info "${smsg}${COLOR_RED}KO - skipped${COLOR_NONE} (${COLOR_BLUE}${desc_field_error}${COLOR_NONE})"
        manage_services_errors=$((manage_services_errors+1))
        return
      fi
      local name=$(echo ${desc_field} | tr -d '\r')
      log_info "${smsg}service definition OK - proceed"
     log_info "--- cfServiceName: ${COLOR_YELLOW}${name}${COLOR_NONE}"
      local sfound=$(cf services | sed -e 1,3d | grep "^${name}" | cat)
      if [[ -z "$sfound" ]]; then
        log_info "${COLOR_BLUE}.... service instance \"${name}\" does not exist - skipped${COLOR_NONE}"
      else
        cf delete-service ${name} -f >/dev/null 2>&1
        log_info "${COLOR_GREEN}.... deleted${COLOR_NONE}"
      fi
      ;;
    esac
  }

  function manage_services() {
    local mgt_action=${1}
    export manage_services_errors=0
    # service_files service descriptors for service instances to be created before deployment
    if [[ -d "${CF_SCRIPTS_DIR}/${ENV_TYPE}" ]]; then
      service_dir="${CF_SCRIPTS_DIR}/${ENV_TYPE}"
    else
      service_dir="${CF_SCRIPTS_DIR}"
    fi
    log_info "Looking for service descriptor files into: ${service_dir}"
    service_files=$(ls -l "${service_dir}" | grep "cf-service.json" | cut -d ':' -f2 | cut -d ' ' -f2)
    if [[ -z "$service_files" ]]
    then
      log_info "No service found to manage, expected files are: \\e[33;1m${service_dir}/*.cf-service.json\\e[0m"
      return 0
    fi
    for service_desc in $service_files
    do
      case ${mgt_action} in
      create)
        create_service "$service_desc"
        ;;
      delete)
        delete_service "$service_desc"
        ;;
      esac
    done
    if [[ "$manage_services_errors" > "0" ]]; then
      log_info "${COLOR_RED}Errors while managing service instances - aborted${COLOR_NONE}"
      return 1
    fi
  }

  unscope_variables
  eval_all_secrets

@@ -754,11 +914,11 @@ stages:
  image: $CF_CLI_IMAGE
  services:
    - name: "$TBC_TRACKING_IMAGE"
      command: ["--service", "cloudfoundry", "4.2.0" ]
      command: ["--service", "cloudfoundry", "4.1.0" ]
  before_script:
    # forcing en-US locale so we can parse cf commands output if necessary
    - cf config --locale "en-US"
    - !reference [.cf-scripts]
    - *cf-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"

# Deploy job prototype
@@ -774,6 +934,7 @@ stages:
# @arg ENV_SPACE     : env-specific Cloud Foundry space
# @arg ENV_ZERODOWNTIME: whether or not zero downtime deployment shall be used
# @arg ENV_DOMAIN    : env-specific domain
# @arg ENV_ROUTE_PATH: env-specific route path
# @arg ENV_HOST_NAME : env-specific application hostname to use
# @arg ENV_RETIRED_APP_SUFFIX : If set, the app old version is not deleted/overriden but renamed with this suffix
.cf-deploy:
@@ -782,7 +943,7 @@ stages:
  variables:
    ENV_APP_SUFFIX: "-$CI_ENVIRONMENT_SLUG"
  before_script:
    - !reference [.cf-scripts]
    - *cf-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${ENV_URL:-$CF_URL}" 'Missing required Cloud Foundry url'
    - assert_defined "${ENV_USER:-$CF_USER}" 'Missing required Cloud Foundry user'
@@ -793,6 +954,7 @@ stages:
  script:
    # use $CI_ENVIRONMENT_SLUG for appname to avoid service name constraints (<=50 chars)
    # use $CI_ENVIRONMENT_SLUG for hostname to avoid constraints (<=63 chars)
    - manage_services "create"
    - deploy "$ENV_TYPE" "${ENV_ZERODOWNTIME:-false}" "${ENV_APP_NAME:-${CF_BASE_APP_NAME}${ENV_APP_SUFFIX}}" "${ENV_HOST_NAME:-${CF_BASE_APP_NAME}${ENV_APP_SUFFIX}}" "${ENV_DOMAIN:-${CF_DEFAULT_DOMAIN}}" "${ENV_ROUTE_PATH:-${CF_DEFAULT_ROUTE_PATH}}"
  artifacts:
    name: "$ENV_TYPE env url or cf logs for $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
@@ -822,7 +984,7 @@ stages:
  variables:
    ENV_APP_SUFFIX: "-$CI_ENVIRONMENT_SLUG"
  before_script:
    - !reference [.cf-scripts]
    - *cf-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${ENV_URL:-$CF_URL}" 'Missing required Cloud Foundry url'
    - assert_defined "${ENV_USER:-$CF_USER}" 'Missing required Cloud Foundry user'
@@ -832,6 +994,7 @@ stages:
    - cf login -a ${ENV_URL:-$CF_URL} -u ${ENV_USER:-$CF_USER} -p "${ENV_PASSWORD:-$CF_PASSWORD}" -o ${ENV_ORG:-$CF_ORG} -s $ENV_SPACE
  script:
    - delete "$ENV_TYPE" ${ENV_APP_NAME:-${CF_BASE_APP_NAME}${ENV_APP_SUFFIX}}
    - manage_services "delete"
  environment:
    action: stop

@@ -901,7 +1064,7 @@ cf-cleanup-all-review:
  stage: deploy
  dependencies: []
  before_script:
    - !reference [.cf-scripts]
    - *cf-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - assert_defined "${CF_REVIEW_URL:-$CF_URL}" 'Missing required env $CF_REVIEW_URL or $CF_URL'
    - assert_defined "${CF_REVIEW_USER:-$CF_USER}" 'Missing required env $CF_REVIEW_USER or $CF_USER'