|
|
@ -115,9 +115,355 @@ ansible-galaxy install nmasse-itix.threescale-cicd |
|
|
ansible-playbook -i inventory deploy-api.yaml |
|
|
ansible-playbook -i inventory deploy-api.yaml |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
## Inventory |
|
|
|
|
|
|
|
|
|
|
|
Three kinds of systems can be declared in the inventory and used with this role: |
|
|
|
|
|
|
|
|
|
|
|
- 3scale Admin Portal |
|
|
|
|
|
- Red Hat SSO |
|
|
|
|
|
- APIcast instances |
|
|
|
|
|
|
|
|
|
|
|
The 3scale Admin Portal that will be provisionned is the one that is referenced |
|
|
|
|
|
in the playbook that includes this role. For instance, in the previous example, |
|
|
|
|
|
the provisioned 3scale Admin Portal will be `<TENANT>-admin.3scale.net` because |
|
|
|
|
|
the main playbook specifies `hosts: threescale` and the `threescale` group |
|
|
|
|
|
contains only one host: `<TENANT>-admin.3scale.net`. |
|
|
|
|
|
|
|
|
|
|
|
If you specifies multiple hosts for the 3scale Admin Portal, they all will be |
|
|
|
|
|
provisionned with the exact same configuration (useful for multi-site deployments). |
|
|
|
|
|
|
|
|
|
|
|
To connect to the 3scale Admin Portal, you will have to provide an Access Token |
|
|
|
|
|
having read/write privileges on the Account Management API. You can provide this |
|
|
|
|
|
token at the host level, group level or globally with the |
|
|
|
|
|
`threescale_cicd_access_token` variable. |
|
|
|
|
|
|
|
|
|
|
|
At the host level, it is defined as such: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
[threescale] |
|
|
|
|
|
tenant1-admin.3scale.net threescale_cicd_access_token=123...456 |
|
|
|
|
|
tenant2-admin.3scale.net threescale_cicd_access_token=789...012 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
At the group level, you can define it as such: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
[threescale:vars] |
|
|
|
|
|
threescale_cicd_access_token=123...456 |
|
|
|
|
|
|
|
|
|
|
|
[threescale] |
|
|
|
|
|
tenant1-admin.3scale.net |
|
|
|
|
|
tenant2-admin.3scale.net |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
And you can also define it globally, for instance as playbook vars: |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
|
|
|
- hosts: threescale |
|
|
|
|
|
vars: |
|
|
|
|
|
threescale_cicd_access_token: 123...456 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The Red Hat SSO instance (currently there can only be one), is taken by convention |
|
|
|
|
|
from the `sso` group. The `client_id`/`client_secret` used by Zync to synchronize |
|
|
|
|
|
the 3scale applications are fetched from the inventory variables, as well as the |
|
|
|
|
|
scheme (`http`/`https`) and the target realm. |
|
|
|
|
|
|
|
|
|
|
|
Example: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
[sso] |
|
|
|
|
|
sso.acme.corp client_id=3scale client_secret=123 realm=acme scheme=https |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Otherwise, if you don't want to follow this convention, you can use the |
|
|
|
|
|
corresponding extra variable: `threescale_cicd_sso_issuer_endpoint`. For |
|
|
|
|
|
the previous example, the variable would be: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
threescale_cicd_sso_issuer_endpoint=https://3scale:123@sso.acme.corp/auth/realms/acme |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
If both the `sso` group and the `threescale_cicd_sso_issuer_endpoint` extra |
|
|
|
|
|
variable are specified, the extra variable has precedence over the inventory. |
|
|
|
|
|
|
|
|
|
|
|
The APIcast instances are fetched from the `apicast-sandbox` and `apicast-production` |
|
|
|
|
|
groups. There can only be one hostname in each group and it is the public hostname |
|
|
|
|
|
of each APIcast cluster (not each individual member). |
|
|
|
|
|
|
|
|
|
|
|
Example: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
[apicast-sandbox] |
|
|
|
|
|
api-test.acme.corp scheme=http |
|
|
|
|
|
|
|
|
|
|
|
[apicast-production] |
|
|
|
|
|
api.acme.corp scheme=https |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
If you do not want to follow this convention, you can use the corresponding extra |
|
|
|
|
|
variables: |
|
|
|
|
|
|
|
|
|
|
|
- `threescale_cicd_apicast_sandbox_endpoint` |
|
|
|
|
|
- `threescale_cicd_apicast_production_endpoint` |
|
|
|
|
|
|
|
|
|
|
|
For the previous example, the variables would be: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
threescale_cicd_apicast_sandbox_endpoint=http://api-test.acme.corp |
|
|
|
|
|
threescale_cicd_apicast_production_endpoint=https://api.acme.corp |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
If both the `apicast-*` groups and the `threescale_cicd_apicast_*_endpoint` |
|
|
|
|
|
extra variables are specified, the extra variables have precedence over the |
|
|
|
|
|
inventory. |
|
|
|
|
|
|
|
|
|
|
|
## OpenAPI Specification fields |
|
|
|
|
|
|
|
|
|
|
|
This role currently supports only OpenAPI Specifications v2.0 (aka. Swagger 2.0). |
|
|
|
|
|
|
|
|
|
|
|
The following extended fields of the OpenAPI Specifications can be used: |
|
|
|
|
|
|
|
|
|
|
|
- `x-threescale-system-name`, in the `info` structure is used as basis |
|
|
|
|
|
to construct the system_name for the configuration objects in 3scale. |
|
|
|
|
|
- `x-threescale-smoketests-operation` in a method definition is used to flag |
|
|
|
|
|
one operation as usable for smoke tests. The method needs to be idempotent, |
|
|
|
|
|
read-only and without parameters. If no method is flagged as smoke tests, |
|
|
|
|
|
the smoke tests are just skipped. |
|
|
|
|
|
|
|
|
|
|
|
If the extended fields cannot be used (if for instance you do not want to alter |
|
|
|
|
|
your API Contract), you can use the corresponding extra variable: |
|
|
|
|
|
|
|
|
|
|
|
- `threescale_cicd_api_system_name` |
|
|
|
|
|
- `threescale_cicd_openapi_smoketest_operation` |
|
|
|
|
|
|
|
|
|
|
|
Here is an example of an OpenAPI Specification using those extended fields: |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
|
|
|
swagger: '2.0' |
|
|
|
|
|
info: |
|
|
|
|
|
x-threescale-system-name: 'echo-api' |
|
|
|
|
|
title: 'Echo API' |
|
|
|
|
|
version: '1.0' |
|
|
|
|
|
host: 'echo-api.3scale.net' |
|
|
|
|
|
paths: |
|
|
|
|
|
/: |
|
|
|
|
|
get: |
|
|
|
|
|
operationId: Echo |
|
|
|
|
|
summary: 'Get an echo' |
|
|
|
|
|
description: 'Get an echo from the server' |
|
|
|
|
|
x-threescale-smoketests-operation: true |
|
|
|
|
|
responses: |
|
|
|
|
|
200: |
|
|
|
|
|
description: 'An Echo from the server' |
|
|
|
|
|
security: |
|
|
|
|
|
- apikey: [] |
|
|
|
|
|
securityDefinitions: |
|
|
|
|
|
apikey: |
|
|
|
|
|
name: api-key |
|
|
|
|
|
in: header |
|
|
|
|
|
type: apiKey |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Namely, `echo-api` would be used as a basis to construct the system_name |
|
|
|
|
|
of the 3scale service definition and a `GET` on `/` would be used as |
|
|
|
|
|
smoketests. |
|
|
|
|
|
|
|
|
|
|
|
To achieve the same effect without the OpenAPI extended fields, you would have |
|
|
|
|
|
to pass the following extra variables: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
threescale_cicd_api_system_name=echo-api |
|
|
|
|
|
threescale_cicd_openapi_smoketest_operation=Echo # The operationId of the "GET /" method |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The following standard fields of the OpenAPI Specifications are used. |
|
|
|
|
|
|
|
|
|
|
|
In the `info` section: |
|
|
|
|
|
|
|
|
|
|
|
- `title` is used as the display name of the 3scale service definition. |
|
|
|
|
|
- `version` is used for proper versioning and follows the [semver scheme](https://semver.org/). |
|
|
|
|
|
- `host` is the DNS name of the existing API backend to expose. |
|
|
|
|
|
|
|
|
|
|
|
For each defined method: |
|
|
|
|
|
|
|
|
|
|
|
- the `operationId` fields is used as the system_name for the corresponding |
|
|
|
|
|
methods/metrics. |
|
|
|
|
|
- the `summary` and `description` fields are used as name and description |
|
|
|
|
|
for the methods/metrics. |
|
|
|
|
|
- the `security` and `securityDefinitions` are used to determine the security |
|
|
|
|
|
scheme of the exposed API. |
|
|
|
|
|
|
|
|
|
|
|
To have a one-to-one mapping between the OpenAPI Specifications and the 3scale features, |
|
|
|
|
|
some restrictions are applied on the `security`/`securityDefinitions` structures. |
|
|
|
|
|
Namely, there must be one and exactly one security requirement in the `security` |
|
|
|
|
|
structure. The security requirement needs to be applied globally (not on a per |
|
|
|
|
|
method basis). |
|
|
|
|
|
|
|
|
|
|
|
The security definitions also have restrictions: you can choose between only two |
|
|
|
|
|
security schemes: |
|
|
|
|
|
|
|
|
|
|
|
- OAuth / OpenID Connect |
|
|
|
|
|
- API Key |
|
|
|
|
|
|
|
|
|
|
|
The App Key Pair scheme proposed by 3scale has no corresponding definition in the |
|
|
|
|
|
OpenAPI Specifications and is currently not supported by this role. |
|
|
|
|
|
|
|
|
|
|
|
So to be more concrete, to secure your API with API Key, use this excerpt in your |
|
|
|
|
|
OpenAPI Specification file: |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
|
|
|
securityDefinitions: |
|
|
|
|
|
apikey: |
|
|
|
|
|
name: api-key |
|
|
|
|
|
in: header |
|
|
|
|
|
type: apiKey |
|
|
|
|
|
security: |
|
|
|
|
|
- apikey: [] |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
You can of course, choose the HTTP header name that will be used to send the |
|
|
|
|
|
API Key by changing the `name` field (in this example: `api-key`). |
|
|
|
|
|
|
|
|
|
|
|
And to secure it with OpenID Connect use this excerpt in your OpenAPI |
|
|
|
|
|
Specification file: |
|
|
|
|
|
|
|
|
|
|
|
```yaml |
|
|
|
|
|
securityDefinitions: |
|
|
|
|
|
oidc: |
|
|
|
|
|
type: oauth2 |
|
|
|
|
|
flow: accessCode |
|
|
|
|
|
scopes: |
|
|
|
|
|
openid: Get an OpenID Connect token |
|
|
|
|
|
security: |
|
|
|
|
|
- oidc: |
|
|
|
|
|
- openid |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
You can of course use the OpenID Connect flow of your choice: |
|
|
|
|
|
|
|
|
|
|
|
- `implicit` |
|
|
|
|
|
- `password` |
|
|
|
|
|
- `application` |
|
|
|
|
|
- `accessCode` |
|
|
|
|
|
|
|
|
## Role Variables |
|
|
## Role Variables |
|
|
|
|
|
|
|
|
TODO |
|
|
This section presents extensively all the variables used by this role. As a |
|
|
|
|
|
foreword, this role adopt a convention-over-configuration scheme. This means |
|
|
|
|
|
that sensible defaults and opinionated naming schemes are provided out-of-the-box. |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_openapi_file` |
|
|
|
|
|
|
|
|
|
|
|
Specifies the OpenAPI Specification file to read. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: Complete path to the OpenAPI Specification, on the local filesystem. |
|
|
|
|
|
Avoid relative paths, prefer absolute ones. If you need to read a file that is |
|
|
|
|
|
relative to your playbook, use the `{{ playbook_dir }}` placeholder. |
|
|
|
|
|
- Required: yes |
|
|
|
|
|
- Example: `/tmp/openapi.yaml` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_openapi_file_format` |
|
|
|
|
|
|
|
|
|
|
|
Specifies the format (JSON or YAML) of the OpenAPI Specification file to read. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: `JSON` or `YAML` |
|
|
|
|
|
- Required: yes |
|
|
|
|
|
- Example: `YAML` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_api_system_name` |
|
|
|
|
|
|
|
|
|
|
|
Defines the system_name of the 3scale Service that will be provisioned. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: lower case alphanumeric + underscore |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: if not defined, the system_name is taken from the OpenAPI |
|
|
|
|
|
Specification `x-threescale-system-name` extended field, suffixed by the |
|
|
|
|
|
API major version number. If there is no `x-threescale-system-name` |
|
|
|
|
|
extended field can be found, the `title` field is sanitized and then used. |
|
|
|
|
|
If no title can be found, the default value `API` is used. If no version |
|
|
|
|
|
number can be found, `0` is used. |
|
|
|
|
|
- Example: `my_wonderful_service` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_wildcard_domain` |
|
|
|
|
|
|
|
|
|
|
|
Automatically defines the APIcast public URLs based on a scheme. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: DNS domain suffix |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: if defined, computes the `threescale_cicd_apicast_sandbox_endpoint` |
|
|
|
|
|
and `threescale_cicd_apicast_production_endpoint` from the API system_name. |
|
|
|
|
|
The sandbox APIcast will be `<system_name>-staging.<wildcard_domain>` and the |
|
|
|
|
|
production APIcast will be `<system_name>.<wildcard_domain>`. The suffix for the |
|
|
|
|
|
staging (`-staging`) and the production (empty) can be customized with the |
|
|
|
|
|
`threescale_cicd_default_staging_suffix` and `threescale_cicd_default_production_suffix` |
|
|
|
|
|
variables. |
|
|
|
|
|
- Example: the following two variables |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
threescale_cicd_wildcard_domain=acme.corp |
|
|
|
|
|
threescale_cicd_api_system_name=my_wonderful_service |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
are equivalent to: |
|
|
|
|
|
|
|
|
|
|
|
```ini |
|
|
|
|
|
threescale_cicd_apicast_sandbox_endpoint=https://my-wonderful-service-staging.acme.corp/ |
|
|
|
|
|
threescale_cicd_apicast_production_endpoint=https://my-wonderful-service.acme.corp/ |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_api_backend_hostname` |
|
|
|
|
|
|
|
|
|
|
|
Defines the backend hostname, overriding the `host` field of the OpenAPI Specification. |
|
|
|
|
|
The resulting value is used to define the `threescale_cicd_private_base_url` variable |
|
|
|
|
|
if missing. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: FQDN with an optional port |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: the `host` field of the OpenAPI Specification. |
|
|
|
|
|
- Examples: `mybackend.acme.corp` or `mybackend.acme.corp:8080` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_api_backend_scheme` |
|
|
|
|
|
|
|
|
|
|
|
Defines the scheme to use to connect to the backend, overriding the `schemes` field of the OpenAPI Specification. |
|
|
|
|
|
The resulting value is used to define the `threescale_cicd_private_base_url` variable |
|
|
|
|
|
if missing. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: `http` or `https` |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: the first item of the `scheme` field of the OpenAPI Specification, |
|
|
|
|
|
defaulting to `http` if missing. |
|
|
|
|
|
- Examples: `https` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_private_base_url` |
|
|
|
|
|
|
|
|
|
|
|
Defines the 3scale Private Base URL. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: `<schem>://<host>:<port>` |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: `<threescale_cicd_api_backend_scheme>://<threescale_cicd_api_backend_hostname>` |
|
|
|
|
|
- Examples: `http://mybackend.acme.corp:8080` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_openapi_smoketest_operation` |
|
|
|
|
|
|
|
|
|
|
|
Defines the OpenAPI Specification method to use for smoke tests. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: the `operationId` of the OpenAPI Specification method |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: none. If this variable is undefined and if there is no operation |
|
|
|
|
|
flagged with `x-threescale-system-name` in the OpenAPI Specification, the |
|
|
|
|
|
smoke tests are skipped. |
|
|
|
|
|
- Examples: `http://mybackend.acme.corp:8080` |
|
|
|
|
|
|
|
|
|
|
|
### `threescale_cicd_api_environment_name` |
|
|
|
|
|
|
|
|
|
|
|
Prefix all services with an environment name to prevent any name collision |
|
|
|
|
|
when deploying the same API multiple times on the same 3scale instance. |
|
|
|
|
|
|
|
|
|
|
|
- Syntax: lowercase, alphanumeric + underscore |
|
|
|
|
|
- Required: no |
|
|
|
|
|
- Default value: none, no prefixing is performed. |
|
|
|
|
|
- Examples: `dev`, `test` or `prod` |
|
|
|
|
|
|
|
|
## Dependencies |
|
|
## Dependencies |
|
|
|
|
|
|
|
|
|