Commit 1cff6d0a authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

Merge branch 'feat/route_path' into 'master'

Add CF route path support through env variables

Closes #28

See merge request to-be-continuous/cloud-foundry!57
parents 81fbf37d cf7619cd
Loading
Loading
Loading
Loading
+20 −11
Original line number Diff line number Diff line
@@ -55,17 +55,18 @@ include:

The Cloud Foundry template uses some global configuration used throughout all jobs.

| Name                   | description                            | default value     |
| Name                   | Description                            | Default Value     |
| ---------------------- | -------------------------------------- | ----------------- |
| `CF_CLI_IMAGE`         | the Docker image used to run CF CLI commands <br/>:warning: **set the version required by your Cloud Foundry server** | `registry.hub.docker.com/governmentpaas/cf-cli` |
| `CF_CLI_IMAGE`         | The Docker image used to run CF CLI commands <br/>:warning: **set the version required by your Cloud Foundry server** | `registry.hub.docker.com/governmentpaas/cf-cli` |
| `CF_MANIFEST_BASENAME` | CF manifest file basename (without extension nor env suffix) | `manifest`            |
| `CF_URL`               | Default CF API url                     | **has to be defined** |
| :lock: `CF_USER`       | Default CF user name                   | **has to be defined** |
| :lock: `CF_PASSWORD`   | Default CF user password               | **has to be defined** |
| `CF_ORG`               | Default CF organization for project    | **has to be defined** |
| `CF_BASE_APP_NAME`     | Base application name                  | `$CI_PROJECT_NAME` ([see GitLab doc](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)) |
| `CF_DEFAULT_DOMAIN`    | default CF domain _(only define if you want to use a different domain from CF default)_ | _none_ |
| `CF_SCRIPTS_DIR`       | directory where CF scripts (manifest, hook scripts) are located| `.` _(root project dir)_ |
| `CF_DEFAULT_DOMAIN`    | Default CF domain _(only define if you want to use a different domain from CF default)_ | _none_ |
| `CF_DEFAULT_ROUTE_PATH`     | Default CF route path                  | _none_ |
| `CF_SCRIPTS_DIR`       | Directory where CF scripts (manifest, hook scripts) are located| `.` _(root project dir)_ |

### Secrets management

@@ -112,13 +113,14 @@ Here are variables supported to configure review environments:
| `CF_REVIEW_ORG`       | CF organization for `review` env _(only define if different from default)_    | `$CF_ORG` |
| `CF_REVIEW_APP_NAME`  | Application name for `review` env      | `"${CF_BASE_APP_NAME}-${CI_ENVIRONMENT_SLUG}"` |
| `CF_REVIEW_DOMAIN`    | CF domain for `review` env             | `$CF_DEFAULT_DOMAIN` |
| `CF_REVIEW_HOST_NAME` | application host name for `review` env | `"${CF_BASE_APP_NAME}-${CI_ENVIRONMENT_SLUG}"` (ex: `myproject-review-fix-bug-12`) |
| `CF_REVIEW_HOST_NAME` | Application host name for `review` env | `"${CF_BASE_APP_NAME}-${CI_ENVIRONMENT_SLUG}"` (ex: `myproject-review-fix-bug-12`) |
| `CF_REVIEW_ZERODOWNTIME` | Enables zero-downtime deployment on `review` env| `false` |
| `CF_REVIEW_ENVIRONMENT_SCHEME` | The review environment protocol scheme | `https` |
| `CF_REVIEW_ENVIRONMENT_DOMAIN` | The review environment domain | _none_ |
| `CF_REVIEW_ROUTE_PATH` | CF route path for `review` env | `$CF_DEFAULT_ROUTE_PATH` |
| `CF_REVIEW_RETIRED_APP_SUFFIX` | If set, the app old version is not deleted/overriden but renamed with this suffix | _none_ |

Note: By default review `environment.url` will be built as `${CF_REVIEW_ENVIRONMENT_SCHEME}://${$CI_PROJECT_NAME}-${CI_ENVIRONMENT_SLUG}.${CF_REVIEW_ENVIRONMENT_DOMAIN}`
Note: By default review `environment.url` will be built as `${CF_REVIEW_ENVIRONMENT_SCHEME}://${$CI_PROJECT_NAME}-${CI_ENVIRONMENT_SLUG}.${CF_REVIEW_ENVIRONMENT_DOMAIN}/${CF_REVIEW_ROUTE_PATH}`

#### Integration environment

@@ -137,7 +139,8 @@ Here are variables supported to configure the integration environment:
| `CF_INTEG_ORG`        | CF organization for `integration` env _(only define if different from default)_   | `$CF_ORG` |
| `CF_INTEG_APP_NAME`   | Application name for `integration` env | `"${CF_BASE_APP_NAME}-integration"` |
| `CF_INTEG_DOMAIN`     | CF domain for `integration` env        | `$CF_DEFAULT_DOMAIN` |
| `CF_INTEG_HOST_NAME`  | application host name for `integration` env| `"${CF_BASE_APP_NAME}-integration"` |
| `CF_INTEG_ROUTE_PATH`     | CF route path for `integration` env | `$CF_DEFAULT_ROUTE_PATH` |
| `CF_INTEG_HOST_NAME`  | Application host name for `integration` env| `"${CF_BASE_APP_NAME}-integration"` |
| `CF_INTEG_ZERODOWNTIME`  | Enables zero-downtime deployment on `integration` env| `false` |
| `CF_INTEG_ENVIRONMENT_URL`     | The integration environment url **including scheme** (ex: `https://my-application-integration.nonpublic.domain.com`). Do not use variable inside variable definition as it will result in a two level cascade variable and gitlab does not allow that. | _none_ |
| `CF_INTEG_RETIRED_APP_SUFFIX` | If set, the app old version is not deleted/overriden but renamed with this suffix | _none_ |
@@ -160,7 +163,8 @@ Here are variables supported to configure the staging environment:
| `CF_STAGING_ORG`      | CF organization for `staging` env _(only define if different from default)_   | `$CF_ORG` |
| `CF_STAGING_APP_NAME` | Application name for `staging` env     | `"${CF_BASE_APP_NAME}-staging"` |
| `CF_STAGING_DOMAIN`   | CF domain for `staging` env            | `$CF_DEFAULT_DOMAIN` |
| `CF_STAGING_HOST_NAME`| application host name for `staging` env| `"${CF_BASE_APP_NAME}-staging"` |
| `CF_STAGING_ROUTE_PATH`   | CF route path for `integration` env | `$CF_DEFAULT_ROUTE_PATH` |
| `CF_STAGING_HOST_NAME`| Application host name for `staging` env| `"${CF_BASE_APP_NAME}-staging"` |
| `CF_STAGING_ZERODOWNTIME` | Enables zero-downtime deployment on `staging` env| `false` |
| `CF_STAGING_ENVIRONMENT_URL`   | The staging environment url **including scheme** (ex: `https://my-application-staging.nonpublic.domain.com`). Do not use variable inside variable definition as it will result in a two level cascade variable and gitlab does not allow that. | _none_ |
| `CF_STAGING_RETIRED_APP_SUFFIX` | If set, the app old version is not deleted/overriden but renamed with this suffix | _none_ |
@@ -182,7 +186,8 @@ Here are variables supported to configure the production environment:
| `CF_PROD_ORG`         | CF organization for `production` env _(only define if different from default)_| `$CF_ORG` |
| `CF_PROD_APP_NAME`    | Application name for `production` env  | `$CF_BASE_APP_NAME` |
| `CF_PROD_DOMAIN`      | CF domain for `production` env         | `$CF_DEFAULT_DOMAIN` |
| `CF_PROD_HOST_NAME`   | application host name for `production` env| `$CF_BASE_APP_NAME` |
| `CF_PROD_ROUTE_PATH` | CF domain for `production` env | `$CF_DEFAULT_DOMAIN` |
| `CF_PROD_HOST_NAME`   | Application host name for `production` env| `$CF_DEFAULT_ROUTE_PATH` |
| `CF_PROD_DEPLOY_STRATEGY`| Defines the deployment to production strategy. One of `manual` (i.e. _one-click_) or `auto`. | `manual` |
| `CF_PROD_ZERODOWNTIME`| Enables zero-downtime deployment on `production` env | `true` |
| `CF_PROD_ENVIRONMENT_URL`      | The production environment url **including scheme** (ex: `https://my-application.public.domain.com`) Do not use variable inside variable definition as it will result in a two level cascade variable and gitlab does not allow that. | _none_ |
@@ -219,6 +224,7 @@ Deployment hook scripts may use the following environment variables:
  from `$appname` during a blue/green deployment for instance)
* `$hostname`: the current hostname being used during the deployment in this environment 
* `$domain`: the Cloud Foundry domain being used during the deployment in this environment
* `$routepath`: the Cloud Foundry route path being used during the deployment in this environment
* any [GitLab CI environment](https://docs.gitlab.com/ee/ci/variables/#predefined-environment-variables).

#### cleanup hooks
@@ -288,12 +294,15 @@ Here is the general recommendation (for each one of your environments):
    * do not declare any route in the manifest,
    * set the `$CF_xxx_HOST_NAME` variable to override the hostname to use (or leave unset to use default),
    * set the `$CF_DEFAULT_DOMAIN` or `$CF_xxx_DOMAIN` variable to define the domain to use (or leave unset if you wish 
      to use the default CF domain).
      to use the default CF domain),
    * set the `$CF_DEFAULT_ROUTE_PATH` or `$CF_xxx_ROUTE_PATH` variable to define the route path to use (or leave unset if you wish 
      to use none).
* if the application is mapped to **several routes**:
    * declare the [routes in your manifest](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest-attributes.html#routes),
      possibly using `((appname))` and `((hostname))` variables,
    * set the `$CF_xxx_HOST_NAME` variable to override the hostname to use (or leave unset to use default),
    * `$CF_DEFAULT_DOMAIN` or `$CF_xxx_DOMAIN` variables won't be used. 
    * `$CF_DEFAULT_DOMAIN` or `$CF_xxx_DOMAIN` variables won't be used,
    * `$CF_DEFAULT_ROUTE_PATH` or `$CF_xxx_ROUTE_PATH` variables won't be used. 

### `cf-cleanup-all-review` job

+41 −1
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@
      "description": "Global Cloud Foundry default CF domain _(only define if you want to use a different domain from CF default)_",
      "advanced": true
    },
    {
      "name": "CF_DEFAULT_ROUTE_PATH",
      "description": "Global Cloud Foundry default CF route path _(only define if you want to add a route path to your application route)_",
      "advanced": true
    },
    {
      "name": "CF_USER",
      "description": "Global Cloud Foundry username",
@@ -80,9 +85,14 @@
        },
        {
          "name": "CF_REVIEW_ENVIRONMENT_DOMAIN",
          "description": "The review environment domain (ex: `noprod-cloudfoundry.domain.com`).\n\nBy default review `environment.url` will be built as `${CF_REVIEW_ENVIRONMENT_SCHEME}://${$CI_PROJECT_NAME}-${CI_ENVIRONMENT_SLUG}.${CF_REVIEW_ENVIRONMENT_DOMAIN}`",
          "description": "The review environment domain (ex: `noprod-cloudfoundry.domain.com`).\n\nBy default review `environment.url` will be built as `${CF_REVIEW_ENVIRONMENT_SCHEME}://${$CI_PROJECT_NAME}-${CI_ENVIRONMENT_SLUG}.${CF_REVIEW_ENVIRONMENT_DOMAIN}/${CF_REVIEW_ROUTE_PATH}`",
          "mandatory": true
        },
        {
          "name": "CF_REVIEW_ROUTE_PATH",
          "description": "The review environment route path",
          "advanced": true
        },
        {
          "name": "CF_REVIEW_ZERODOWNTIME",
          "type": "boolean",
@@ -132,6 +142,16 @@
          "description": "The application name for integration env (only define if different from global)",
          "advanced": true
        },
        {
          "name": "CF_INTEG_DOMAIN",
          "description": "The integration environment domain",
          "mandatory": true
        },
        {
          "name": "CF_INTEG_ROUTE_PATH",
          "description": "The integration environment route path",
          "advanced": true
        },
        {
          "name": "CF_INTEG_ENVIRONMENT_URL",
          "type": "url",
@@ -182,6 +202,16 @@
          "description": "The application name for staging env (only define if different from global)",
          "advanced": true
        },
        {
          "name": "CF_STAGING_DOMAIN",
          "description": "The staing environment domain",
          "mandatory": true
        },
        {
          "name": "CF_STAGING_ROUTE_PATH",
          "description": "The staging environment route path",
          "advanced": true
        },
        {
          "name": "CF_STAGING_ENVIRONMENT_URL",
          "type": "url",
@@ -232,6 +262,16 @@
          "description": "The application name for production env (only define if different from global)",
          "advanced": true
        },
        {
          "name": "CF_PROD_DOMAIN",
          "description": "The production environment domain",
          "mandatory": true
        },
        {
          "name": "CF_PROD_ROUTE_PATH",
          "description": "The production environment route path",
          "advanced": true
        },
        {
          "name": "CF_PROD_ENVIRONMENT_URL",
          "type": "url",
+58 −32
Original line number Diff line number Diff line
@@ -50,23 +50,33 @@ variables:
  # [mandatory] CF_ORG                : the Cloud Foundry Organization name

  # [optional]  CF_REVIEW_SPACE       : the Cloud Foundry space for review (disabled if undefined)
  # [optional]  CF_INTEG_SPACE        : the Cloud Foundry space for integration (disabled if undefined - i.e. continuous deployment strategy)
  # [optional]  CF_STAGING_SPACE      : the Cloud Foundry space for staging (disabled if undefined - i.e. continuous deployment strategy)
  # [mandatory] CF_PROD_SPACE         : the Cloud Foundry space for production

  # [mandatory] CF_DEFAULT_DOMAIN     : the main Cloud Foundry domain
  # [optional]  CF_REVIEW_DOMAIN      : specific Cloud Foundry domain for review (defaults to $CF_DEFAULT_DOMAIN)
  # [optional]  CF_INTEG_DOMAIN       : specific Cloud Foundry domain for integration (defaults to $CF_DEFAULT_DOMAIN)
  # [optional]  CF_STAGING_DOMAIN     : specific Cloud Foundry domain for staging (defaults to $CF_DEFAULT_DOMAIN)
  # [optional]  CF_PROD_DOMAIN        : specific Cloud Foundry domain for production (defaults to $CF_DEFAULT_DOMAIN)

  # [optional]  CF_BASE_APP_NAME      : the base application name (defaults to $CI_PROJECT_NAME)
  # [optional]  CF_REVIEW_APP_NAME    : specific Cloud Foundry application name in review env (defaults to $CF_BASE_APP_NAME-$CI_ENVIRONMENT_SLUG)
  # [optional]  CF_INTEG_APP_NAME     : specific Cloud Foundry application name in integration env (defaults to $CF_BASE_APP_NAME)
  # [optional]  CF_STAGING_APP_NAME   : specific Cloud Foundry application name in staging env (defaults to $CF_BASE_APP_NAME)
  # [optional]  CF_PROD_APP_NAME      : specific Cloud Foundry application name in production env (defaults to $CF_BASE_APP_NAME)

  # [optional]  CF_REVIEW_HOST_NAME   : specific Cloud Foundry host name in review env (defaults to $CF_BASE_APP_NAME-$CI_ENVIRONMENT_SLUG)
  # [optional]  CF_INTEG_HOST_NAME    : specific Cloud Foundry application name in integration env (defaults to $CF_BASE_APP_NAME-integration)
  # [optional]  CF_STAGING_HOST_NAME  : specific Cloud Foundry application name in staging env (defaults to $CF_BASE_APP_NAME-staging)
  # [optional]  CF_PROD_HOST_NAME     : specific Cloud Foundry application name in production env (defaults to $CF_BASE_APP_NAME)

  # [optional]  CF_DEFAULT_ROUTE_PATH : a path added to the exposition route of the application (defaults to none/empty)
  # [optional]  CF_REVIEW_ROUTE_PATH  : a specific route path in review env (defaults to $CF_DEFAULT_ROUTE_PATH)
  # [optional]  CF_INTEG_ROUTE_PATH   : a specific route path in integration env (defaults to $CF_DEFAULT_ROUTE_PATH)
  # [optional]  CF_STAGING_ROUTE_PATH : a specific route path in staging env (defaults to $CF_DEFAULT_ROUTE_PATH)
  # [optional]  CF_PROD_ROUTE_PATH    : a specific route path in production env (defaults to $CF_DEFAULT_ROUTE_PATH)

  CF_BASE_APP_NAME: "$CI_PROJECT_NAME"
  CF_SCRIPTS_DIR: "."
  CF_REVIEW_ENVIRONMENT_SCHEME: "https"
@@ -337,6 +347,7 @@ stages:
    log_info "--- tmpappname: \\e[33;1m${tmpappname}\\e[0m"
    log_info "--- appname: \\e[33;1m${appname}\\e[0m"
    log_info "--- hostname: \\e[33;1m${hostname}\\e[0m"
    log_info "--- routepath: \\e[33;1m${routepath:-(n/a)}\\e[0m"
    log_info "--- manifest: \\e[33;1m${manifestfile}\\e[0m"
    cf_push_args=("$tmpappname" "--vars-file" "$targetvarfile")

@@ -396,7 +407,7 @@ stages:
    if [[ "$map_route_required" ]]
    then
      log_info "--- map route (\\e[33;1m${hostname}.${domain}\\e[0m)"
      cf map-route "$tmpappname" "$domain" --hostname "$hostname"
      cf map-route "$tmpappname" "$domain" --hostname "$hostname" ${routepath:+--path "$routepath"}
    fi
  }

@@ -447,10 +458,19 @@ stages:
    export appname=$2
    export hostname=$3
    export domain=$4
    if [[ -n "$5" ]]
    if [[ "$5" = "/*" ]]
    then
       export routepath="$5"
    elif [[ -z $5 ]]
    then
       export routepath=""
    else
       export routepath="/$5"
    fi
    # 6th argument is explicit target appname (for blue/green)
    if [[ "$6" ]]
    then
      # 5th argument is explicit target appname (for blue/green)
      appname=$5
       appname="$6"
    fi

    # find manifest
@@ -496,6 +516,7 @@ stages:
    app_target=$2
    hostname_target=$3
    domain_target=$4
    vroute_path=$5

    log_info "--- \\e[32mblue_green_deploy\\e[0m (env: \\e[33;1m${env}\\e[0m)"
    app_tmp=${app_target}-tmp
@@ -512,7 +533,7 @@ stages:
      else
        # simple deployment
        log_info "app \\e[33;1m${app_target}\\e[0m not found: proceed with simple deployment"
        simple_deploy "$env" "$app_target" "$hostname_target" "$domain_target"
        simple_deploy "$env" "$app_target" "$hostname_target" "$domain_target" "$vroute_path"
        return 0
      fi
    fi
@@ -523,7 +544,7 @@ stages:
    # try/catch-like pattern
    set -E
    trap 'blue_green_rollback "$app_tmp"' ERR
    simple_deploy "$env" "$app_tmp" "$hostname_tmp" "$domain_tmp" "$app_target"
    simple_deploy "$env" "$app_tmp" "$hostname_tmp" "$domain_tmp" "$vroute_path" "$app_target"
    set +E

    # map target route(s) to "green"
@@ -545,7 +566,7 @@ stages:
        done
    else
        # map route from env
        cf map-route "$app_tmp" "$domain_target" --hostname "$hostname_target"
        cf map-route "$app_tmp" "$domain_target" --hostname "$hostname_target" ${vroute_path:+--path "$vroute_path"}
    fi

    # umap/delete temporary route from "green"
@@ -590,14 +611,15 @@ stages:
    appname=$3
    hostname=$4
    domain=${5:-$(default_domain)}
    routepath=${6}

    if [[ "$zdt" = "true" ]]
    then
      # blue/green deploy
      blue_green_deploy "$env" "$appname" "$hostname" "$domain"
      blue_green_deploy "$env" "$appname" "$hostname" "$domain" "$routepath"
    else
      # simple deploy
      simple_deploy "$env" "$appname" "$hostname" "$domain"
      simple_deploy "$env" "$appname" "$hostname" "$domain" "$routepath"
    fi

    # finally persist environment url
@@ -771,7 +793,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)
    - 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}}
    - 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"
    when: always
@@ -829,6 +851,7 @@ cf-review:
    ENV_ZERODOWNTIME: "$CF_REVIEW_ZERODOWNTIME"
    ENV_DOMAIN: "$CF_REVIEW_DOMAIN"
    ENV_HOST_NAME: "$CF_REVIEW_HOST_NAME"
    ENV_ROUTE_PATH: "$CF_REVIEW_ROUTE_PATH"
    ENV_RETIRED_APP_SUFFIX: "$CF_REVIEW_RETIRED_APP_SUFFIX"
  environment:
    name: review/$CI_COMMIT_REF_NAME
@@ -916,6 +939,7 @@ cf-integration:
    ENV_ZERODOWNTIME: "$CF_INTEG_ZERODOWNTIME"
    ENV_DOMAIN: "$CF_INTEG_DOMAIN"
    ENV_HOST_NAME: "$CF_INTEG_HOST_NAME"
    ENV_ROUTE_PATH: "$CF_INTEG_ROUTE_PATH"
    ENV_RETIRED_APP_SUFFIX: "$CF_INTEG_RETIRED_APP_SUFFIX"
  environment:
    name: integration
@@ -943,6 +967,7 @@ cf-staging:
    ENV_ZERODOWNTIME: "$CF_STAGING_ZERODOWNTIME"
    ENV_DOMAIN: "$CF_STAGING_DOMAIN"
    ENV_HOST_NAME: "$CF_STAGING_HOST_NAME"
    ENV_ROUTE_PATH: "$CF_STAGING_ROUTE_PATH"
    ENV_RETIRED_APP_SUFFIX: "$CF_STAGING_RETIRED_APP_SUFFIX"
  environment:
    name: staging
@@ -970,6 +995,7 @@ cf-production:
    ENV_ZERODOWNTIME: "$CF_PROD_ZERODOWNTIME"
    ENV_DOMAIN: "$CF_PROD_DOMAIN"
    ENV_HOST_NAME: "$CF_PROD_HOST_NAME"
    ENV_ROUTE_PATH: "$CF_PROD_ROUTE_PATH"
    ENV_RETIRED_APP_SUFFIX: "$CF_PROD_RETIRED_APP_SUFFIX"
  environment:
    name: production