Browse Source

see #22: get rid of the set_fact where possible

pull/24/head
Nicolas Massé 7 years ago
parent
commit
75d8eb69c5
  1. 9
      .travis.yml
  2. 84
      README.md
  3. 18
      defaults/main.yml
  4. 11
      tasks/api-calls/update_proxy.yml
  5. 1
      tasks/cleanup.yaml
  6. 2
      tasks/main.yml
  7. 1
      tasks/steps/default_application.yml
  8. 169
      tasks/steps/read_openapi.yml
  9. 7
      tasks/steps/requirements.yml
  10. 46
      tasks/steps/variables_from_inventory.yml
  11. 7
      templates/api-calls/create_service.j2
  12. 4
      templates/api-calls/smoke-test/url.j2
  13. 4
      templates/api-calls/update_proxy.j2
  14. 5
      templates/openapi/apicast_production_endpoint.j2
  15. 5
      templates/openapi/apicast_sandbox_endpoint.j2
  16. 6
      templates/openapi/generate_base_system_name.j2
  17. 4
      templates/openapi/generate_final_system_name.j2
  18. 26
      templates/openapi/openapi_operations.j2
  19. 11
      templates/openapi/private_base_url.j2
  20. 5
      templates/openapi/service_name.j2
  21. 3
      templates/openapi/sso_issuer_endpoint.j2
  22. 4
      templates/rewritten_openapi.j2
  23. 16
      tests/3scale-saas-with-hosted-apicast-apikey.yml
  24. 45
      tests/3scale-saas-with-hosted-apicast-multi-environment.yml
  25. 16
      tests/3scale-saas-with-hosted-apicast-oidc.yml
  26. 16
      tests/3scale-saas-with-hosted-apicast-with-basePath.yml
  27. 10
      tests/inventory.j2
  28. 29
      vars/main.yml

9
.travis.yml

@ -6,13 +6,14 @@ install:
- pip install jmespath - pip install jmespath
script: script:
- ansible-playbook tests/write-inventory-files.yml - ansible-playbook tests/write-inventory-files.yml
- ansible-playbook -i tests/inventory tests/3scale-saas-with-hosted-apicast-apikey.yml - ansible-playbook -v -i tests/inventory tests/3scale-saas-with-hosted-apicast-apikey.yml
- ansible-playbook -i tests/inventory tests/3scale-saas-with-hosted-apicast-oidc.yml - ansible-playbook -v -i tests/inventory tests/3scale-saas-with-hosted-apicast-oidc.yml
- ansible-playbook -i tests/inventory tests/3scale-saas-with-hosted-apicast-with-basePath.yml - ansible-playbook -v -i tests/inventory tests/3scale-saas-with-hosted-apicast-with-basePath.yml
- ansible-playbook -v -i tests/inventory tests/3scale-saas-with-hosted-apicast-multi-environment.yml
env: env:
global: global:
# travis encrypt "THREESCALE_INVENTORY=$(yaml2json tests/3scale-inventory.yaml|base64)" # travis encrypt "THREESCALE_INVENTORY=$(yaml2json tests/3scale-inventory.yaml|base64)"
secure: "YKSBZJonKq/RwBtrg1wrlbw9GUaQhY0LmbUpShIPMeD1DqLQtOz9OIijAP2Uvtnn5F8josyzyYeZoRz4HOWT6DNdbZoclIT86FdT9yp9pIBuKYqaGOMmdwhTl+BXudeTCAvuj4k6eNux24WY+AqWZoXgr4E0rRJQJyD/G7gn4CMDQmn+an+RK43nhkXgMYNm6SHbR3c3wBypdWJivfgvdBfJb2VY8Q3XXQNh+ivUNW5us4Sf+G+UsjbQKeTF6G1rz8FUxGc2tElWcc+6fXWDTWI1WkZVfNm7f6cGii7X22OBDgOkoUjUKeVj/vmpgp7uOSk3XiWIC+gNsT/cS9/6XzZCnfhGmPal3QP5hXnsP5gBfKYzy8zZEp9H8NLyGA8K7M0cZGuFDdxg0HnIyXNnn7Denjyt3TopFR9ENsNOEbBar8XEb4oZicRWrXC9O/Sse4rCm5vGffXt+lcoAuypmxhASDZKNKsQRXhG+JRMZ2ONB8QOdH22mQ+JEOhOFNtiY2O9eEQOdtU92B9vWYWOztSGZ8/+AQ729bCzOw7AfxtxUyYadFnEdibAeWsl+xnlAdwmo0sNoCTGBKFMXlyP/gmcE7NdCLqWS6MSM2u4ARuQt7IS29wwlRseaMUli69vp0SqvjT6lelx4bonLFi74treKIQVLoxqSQaiU7KVTr0=" secure: "SKrCC5Nd1lXFU9mCrmGUSbqmEFGzT6/3KTXGQ/bASgSx4r0AuDHt48cI/XPQ6XGCIGaxAt2oRWzJZJ00+Y+5A1TCYAXI4X75mTVl+mgZ3ul5hSK1/KfPPoLciZIcv678FLmmpryNRapK+zxG+OKR1puNFQm9himhF9x0JICigFZSVLMLGnpvHDo2GguFv+4aO1tkdZMT5IzBlPD11Kn98QVCruF/dHiBXtSxuo5ja0/uDsGotMcUQRNa637WIQ5D7YgDREpeLrHzmbpW2zr7HI30oA68k+BxZFqlQ/cyI7f5ogNE73ID+FBSSxVXqcn7TD2nmYL3NQpMztTCzM6YlODIuAvdWUxggeBJflpIVoza0HLP7CB76GAmRSkvwGbnGAHWvCOtvczmJ/hXGgAEdRL5q3eJiGebRvhb6SAVMZ3LOH9LlLU9fKDVGqzolFi4+Jaxami600zgBB/yGkFckpapUZLEK2O0QdHBu3bjd7+9C0EgYONrbyMMkMoWr8TiX/y0qTHg3SclOEacDqLw3kb0MAe9V9WtE+MKOAM38lkXN1v1J9x2izeEqKBDDuzxMOsRxQwfSlA5MVW1kOiKaQgKl37F5t+msfIsPDlr2DRM4JTsIBaQKMY9E50tQ0cMW+vU7P+kn8UlNdTh53TLwKMjPcU99XG1f95fGAMocAA="
notifications: notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/ webhooks: https://galaxy.ansible.com/api/v1/notifications/
branches: branches:

84
README.md

@ -74,7 +74,8 @@ securityDefinitions:
In this Swagger file, the following fields are used: In this Swagger file, the following fields are used:
- `x-threescale-system-name` is used as system_name for the configuration objects in 3scale. - `x-threescale-system-name` is used as a basis for the system_name for the
configuration objects in 3scale.
- `title` is used as the name of the service definition. - `title` is used as the name of the service definition.
- `version` is used for proper versioning and follows the [semver scheme](https://semver.org/). - `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. - `host` is the DNS name of the existing API backend to expose.
@ -128,12 +129,6 @@ ansible-playbook -i inventory deploy-api.yaml
## Inventory ## 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 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, 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 provisioned 3scale Admin Portal will be `<TENANT>-admin.3scale.net` because
@ -175,60 +170,31 @@ And you can also define it globally, for instance as playbook vars:
threescale_cicd_access_token: 123...456 threescale_cicd_access_token: 123...456
``` ```
The Red Hat SSO instance (currently there can only be one), is taken by convention The Red Hat SSO instance (currently there can only be one), is defined by
from the `sso` group. The `client_id`/`client_secret` used by Zync to synchronize the `threescale_cicd_sso_issuer_endpoint` variable of the `threescale` group.
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 Its syntax is `https://<client_id>:<client_secret>@hostname/auth/realms/<realm>`.
variable are specified, the extra variable has precedence over the inventory. The `client_id`/`client_secret` are used by Zync to synchronize the 3scale
applications with Red Hat SSO.
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: Example:
```ini ```ini
[apicast-sandbox] threescale_cicd_sso_issuer_endpoint=https://3scale:123@sso.acme.corp/auth/realms/acme
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 The APIcast instances are defined from the following extra variables:
variables:
- `threescale_cicd_apicast_sandbox_endpoint` - `threescale_cicd_apicast_sandbox_endpoint`
- `threescale_cicd_apicast_production_endpoint` - `threescale_cicd_apicast_production_endpoint`
For the previous example, the variables would be: Example:
```ini ```ini
threescale_cicd_apicast_sandbox_endpoint=http://api-test.acme.corp threescale_cicd_apicast_sandbox_endpoint=http://api-test.acme.corp
threescale_cicd_apicast_production_endpoint=https://api.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 ## OpenAPI Specification fields
This role currently supports only OpenAPI Specifications v2.0 (aka. Swagger 2.0). This role currently supports only OpenAPI Specifications v2.0 (aka. Swagger 2.0).
@ -245,7 +211,7 @@ The following extended fields of the OpenAPI Specifications can be used:
If the extended fields cannot be used (if for instance you do not want to alter 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: your API Contract), you can use the corresponding extra variable:
- `threescale_cicd_api_system_name` - `threescale_cicd_api_base_system_name`
- `threescale_cicd_openapi_smoketest_operation` - `threescale_cicd_openapi_smoketest_operation`
Here is an example of an OpenAPI Specification using those extended fields: Here is an example of an OpenAPI Specification using those extended fields:
@ -284,7 +250,7 @@ To achieve the same effect without the OpenAPI extended fields, you would have
to pass the following extra variables: to pass the following extra variables:
```ini ```ini
threescale_cicd_api_system_name=echo-api threescale_cicd_api_base_system_name=echo-api
threescale_cicd_openapi_smoketest_operation=Echo # The operationId of the "GET /" method threescale_cicd_openapi_smoketest_operation=Echo # The operationId of the "GET /" method
``` ```
@ -389,14 +355,28 @@ Defines the system_name of the 3scale Service that will be provisioned.
- **Syntax:** lower case alphanumeric + underscore - **Syntax:** lower case alphanumeric + underscore
- **Required:** no - **Required:** no
- **Default value:** if not defined, the system_name is taken from the OpenAPI - **Default value:** if not defined, the system_name is taken from the
Specification `x-threescale-system-name` extended field, suffixed by the `threescale_cicd_api_base_system_name` variable. This base system_name
API major version number. If no `x-threescale-system-name` extended field is then suffixed by the API major version number and prefixed by the
can be found, the `title` field is sanitized and then used. environment name (only if `threescale_cicd_api_environment_name` is defined).
- **Example:** `dev_my_wonderful_service_1`
### `threescale_cicd_api_base_system_name`
Is used as a basis to compute the `threescale_cicd_api_system_name`.
- **Syntax:** lower case alphanumeric + underscore
- **Required:** no
- **Default value:** if not defined, the OpenAPI Specification
`x-threescale-system-name` extended field or as a last resort, the `title`
field is sanitized and then used.
If no title can be found, the default value `API` is used. If no version If no title can be found, the default value `API` is used. If no version
number can be found, `0` is used. number can be found, `0` is used.
- **Example:** `my_wonderful_service` - **Example:** `my_wonderful_service`
Note: If both `threescale_cicd_api_base_system_name` and `threescale_cicd_api_system_name`
are set, the later has precedence.
### `threescale_cicd_wildcard_domain` ### `threescale_cicd_wildcard_domain`
Automatically defines the APIcast public URLs based on a scheme. Automatically defines the APIcast public URLs based on a scheme.
@ -414,7 +394,7 @@ Automatically defines the APIcast public URLs based on a scheme.
```ini ```ini
threescale_cicd_wildcard_domain=acme.corp threescale_cicd_wildcard_domain=acme.corp
threescale_cicd_api_system_name=my_wonderful_service threescale_cicd_api_base_system_name=my_wonderful_service
``` ```
are equivalent to: are equivalent to:
@ -479,7 +459,7 @@ when deploying the same API multiple times on the same 3scale instance.
### Miscellaneous variables ### Miscellaneous variables
Miscellaneous variables defined in [defaults/main.yml](defaults/main.yml]) Miscellaneous variables defined in [defaults/main.yml](defaults/main.yml)
provide sensible defaults. Have a look at them. provide sensible defaults. Have a look at them.
## Dependencies ## Dependencies

18
defaults/main.yml

@ -17,10 +17,12 @@ threescale_cicd_application_plans:
state: hidden state: hidden
name: Ansible Test Plan name: Ansible Test Plan
# Specifies that APIcast is self managed (if a public staging and/or # APIcast public base URLs
# production URL is given), or hosted threescale_cicd_apicast_sandbox_endpoint: '{{ lookup(''template'', ''openapi/apicast_sandbox_endpoint.j2'') }}'
threescale_cicd_api_deployment_type: '{{ ''self_managed'' if threescale_cicd_apicast_sandbox_endpoint is defined or threescale_cicd_apicast_production_endpoint is defined else ''hosted'' }}' threescale_cicd_apicast_production_endpoint: '{{ lookup(''template'', ''openapi/apicast_production_endpoint.j2'') }}'
# SSO Issuer Endpoint
threescale_cicd_sso_issuer_endpoint: '{{ lookup(''template'', ''openapi/sso_issuer_endpoint.j2'') }}'
## ##
## Default Application (used for Smoke Tests) ## Default Application (used for Smoke Tests)
## ##
@ -35,3 +37,13 @@ threescale_cicd_default_application_plan: '{{ (threescale_cicd_application_plans
# of app, api and environment data, hashed toghether to produce a stable id. # of app, api and environment data, hashed toghether to produce a stable id.
threescale_cicd_default_application_appid: '{{ (threescale_cicd_default_application_name ~ threescale_cicd_api_system_name ~ threescale_cicd_access_token)|hash(''sha1'') }}' threescale_cicd_default_application_appid: '{{ (threescale_cicd_default_application_name ~ threescale_cicd_api_system_name ~ threescale_cicd_access_token)|hash(''sha1'') }}'
threescale_cicd_default_application_appsecret: '{{ (''secret'' ~ threescale_cicd_default_application_name ~ threescale_cicd_api_system_name ~ threescale_cicd_access_token)|hash(''sha1'') }}' threescale_cicd_default_application_appsecret: '{{ (''secret'' ~ threescale_cicd_default_application_name ~ threescale_cicd_api_system_name ~ threescale_cicd_access_token)|hash(''sha1'') }}'
# The OpenAPI Operation to use for the smoketest
threescale_cicd_openapi_smoketest_operation: '{{ threescale_cicd_openapi_file_content|json_query(''paths.*.get[? "x-threescale-smoketests-operation" ].operationId|[0]'')|default("")|regex_replace(''[^0-9a-zA-Z_]+'', ''_'') }}'
##
## OpenAPI Specification File parsing
##
threescale_cicd_api_base_system_name: '{{ lookup(''template'', ''openapi/generate_base_system_name.j2'') }}'
threescale_cicd_api_system_name: '{{ lookup(''template'', ''openapi/generate_final_system_name.j2'') }}'
threescale_cicd_private_base_url: '{{ lookup(''template'', ''openapi/private_base_url.j2'') }}'

11
tasks/api-calls/update_proxy.yml

@ -13,15 +13,10 @@
register: threescale_cicd_tmpresponse register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200' changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Extract the staging gateway endpoint from the proxy definition - name: Extract the staging and production gateway endpoint from the proxy definition
set_fact: set_fact:
threescale_cicd_apicast_sandbox_endpoint: '{{ threescale_cicd_tmpresponse.json.proxy.sandbox_endpoint }}' threescale_cicd_apicast_discovered_sandbox_endpoint: '{{ threescale_cicd_tmpresponse.json.proxy.sandbox_endpoint }}'
when: "threescale_cicd_apicast_sandbox_endpoint is not defined" threescale_cicd_apicast_discovered_production_endpoint: '{{ threescale_cicd_tmpresponse.json.proxy.endpoint }}'
- name: Extract the production gateway endpoint from the proxy definition
set_fact:
threescale_cicd_apicast_production_endpoint: '{{ threescale_cicd_tmpresponse.json.proxy.endpoint }}'
when: "threescale_cicd_apicast_production_endpoint is not defined"
- name: Wait for a couple seconds - name: Wait for a couple seconds
pause: pause:

1
tests/cleanup.yaml → tasks/cleanup.yaml

@ -9,6 +9,7 @@
register: threescale_cicd_tmpresponse register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200' changed_when: 'threescale_cicd_tmpresponse.status == 200'
when: 'threescale_cicd_api_service_id is defined' when: 'threescale_cicd_api_service_id is defined'
- name: Delete the created ActiveDocs - name: Delete the created ActiveDocs
uri: uri:
url: 'https://{{ inventory_hostname }}/admin/api/active_docs/{{ threescale_cicd_api_activedocs_id }}.json?access_token={{ threescale_cicd_access_token|urlencode }}' url: 'https://{{ inventory_hostname }}/admin/api/active_docs/{{ threescale_cicd_api_activedocs_id }}.json?access_token={{ threescale_cicd_access_token|urlencode }}'

2
tasks/main.yml

@ -3,7 +3,7 @@
# Make sure we have everything we need to run this playbook # Make sure we have everything we need to run this playbook
- import_tasks: steps/requirements.yml - import_tasks: steps/requirements.yml
# Compute missing variables from the inventory # Warn the user about those deprecated features
- import_tasks: steps/variables_from_inventory.yml - import_tasks: steps/variables_from_inventory.yml
# Load the API definition from the provided OpenAPI file # Load the API definition from the provided OpenAPI file

1
tasks/steps/default_application.yml

@ -4,7 +4,6 @@
when: 'threescale_cicd_default_account_id is not defined' when: 'threescale_cicd_default_account_id is not defined'
- import_tasks: "api-calls/find_application.yml" - import_tasks: "api-calls/find_application.yml"
when: 'threescale_cicd_default_application_id is not defined'
- import_tasks: "api-calls/update_application.yml" - import_tasks: "api-calls/update_application.yml"
when: 'threescale_cicd_default_application_id is defined' when: 'threescale_cicd_default_application_id is defined'

169
tasks/steps/read_openapi.yml

@ -1,17 +1,4 @@
--- ---
- name: Parse the OpenAPI file (YAML format)
set_fact:
threescale_cicd_openapi_file_content: '{{ lookup(''file'', threescale_cicd_openapi_file) |from_yaml }}'
when: "threescale_cicd_openapi_file_format|upper == 'YAML'"
- name: Parse the OpenAPI file (JSON format)
set_fact:
threescale_cicd_openapi_file_content: '{{ lookup(''file'', threescale_cicd_openapi_file) |from_json }}'
when: "threescale_cicd_openapi_file_format|upper == 'JSON'"
- name: Extract the OpenAPI format version
set_fact:
threescale_cicd_openapi_file_version: '{{ threescale_cicd_openapi_file_content|json_query(''swagger'') }}'
- name: Check the OpenAPI format version - name: Check the OpenAPI format version
assert: assert:
@ -19,155 +6,27 @@
- "threescale_cicd_openapi_file_version == '2.0'" - "threescale_cicd_openapi_file_version == '2.0'"
msg: "Currently only the OpenAPI/Swagger 2.0 is handled. If needed, fill an issue or submit a pull request!" msg: "Currently only the OpenAPI/Swagger 2.0 is handled. If needed, fill an issue or submit a pull request!"
# TODO rewrite this in a more "Ansible compatible" way
- name: Extract API Methods
set_fact:
threescale_cicd_api_name: '{{ threescale_cicd_openapi_file_content.info.title|default("API") }}'
threescale_cicd_api_description: '{{ threescale_cicd_openapi_file_content.info.description|default("") }}'
threescale_cicd_api_version: '{{ threescale_cicd_openapi_file_content.info.version|default("0.0.1") }}'
threescale_cicd_api_basepath: '{{ threescale_cicd_openapi_file_content.basePath|default("") }}'
threescale_cicd_api_operations: >-
{% set operations = {} -%}
{% if 'paths' in threescale_cicd_openapi_file_content -%}
{% for path, verbs in threescale_cicd_openapi_file_content['paths'].items() -%}
{% if path.startswith('/') -%}
{% for verb, method_description in verbs.items() -%}
{% if verb != '$ref' and verb != 'parameters' -%}
{% if 'operationId' in method_description -%}
{% set operation_id = method_description['operationId'] -%}
{% else -%}
{% set operation_id = verb.upper() + path -%}
{% endif -%}
{% set operation_id = operation_id|regex_replace('[^0-9a-zA-Z_]+', '_') -%}
{% set operation = { operation_id: { 'path': path, 'verb': verb } } -%}
{% if 'summary' in method_description -%}
{% if operation[operation_id].update({ 'friendly_name': method_description.summary }) -%}{% endif -%}
{% endif -%}
{% if 'description' in method_description -%}
{% if operation[operation_id].update({ 'description': method_description.description }) -%}{% endif -%}
{% endif -%}
{% if operations.update(operation) -%}{% endif -%}
{% endif -%}
{% endfor -%}
{% endif -%}
{% endfor -%}
{% endif -%}
{{ operations }}
- name: Extract components from the version number
set_fact:
threescale_cicd_api_version_components: '{{ threescale_cicd_api_version.split(".") }}'
- name: Find the major version
set_fact:
threescale_cicd_api_version_major: '{{ threescale_cicd_api_version_components|first }}'
- name: Compute the system_name suffix to append to the generated system_name
set_fact:
threescale_cicd_api_system_name_suffix: '{{ (threescale_cicd_api_system_name is not defined)|ternary("_" ~ (threescale_cicd_api_version_major|regex_replace(''[^a-zA-Z0-9_]+'', ''_'')), "") }}'
- name: Compute the system_name prefix to prepend to the generated system_name
set_fact:
threescale_cicd_api_system_name_prefix: '{{ (threescale_cicd_api_system_name is not defined and threescale_cicd_api_environment_name is defined)|ternary((threescale_cicd_api_environment_name|default("")|regex_replace(''[^a-zA-Z0-9_]+'', ''_'')) ~ "_", "") }}'
- name: Extract the wanted system_name from OpenAPI
set_fact:
threescale_cicd_api_system_name: '{{ threescale_cicd_openapi_file_content.info[''x-threescale-system-name'']|regex_replace(''[^a-zA-Z0-9_]+'', ''_'')|lower }}'
when: 'threescale_cicd_api_system_name is not defined and ''x-threescale-system-name'' in threescale_cicd_openapi_file_content.info'
- name: Generate a system_name from the API title
set_fact:
threescale_cicd_api_system_name: '{{ threescale_cicd_openapi_file_content.info[''title'']|default(''api'')|regex_replace(''[^a-zA-Z0-9_]+'', ''_'')|lower }}'
when: 'threescale_cicd_api_system_name is not defined'
- name: Append the major version to the system_name
set_fact:
threescale_cicd_api_system_name: '{{ threescale_cicd_api_system_name }}{{ threescale_cicd_api_system_name_suffix }}'
- name: Set the threescale_cicd_apicast_{sandbox,production}_endpoint variable from the wildcard domain
set_fact:
threescale_cicd_apicast_sandbox_endpoint: '{{ threescale_cicd_default_apicast_scheme }}://{{ threescale_cicd_api_system_name|regex_replace(''[^a-zA-Z0-9-]+'', ''-'')|lower }}{{ threescale_cicd_default_staging_suffix }}.{{ threescale_cicd_wildcard_domain }}'
threescale_cicd_apicast_production_endpoint: '{{ threescale_cicd_default_apicast_scheme }}://{{ threescale_cicd_api_system_name|regex_replace(''[^a-zA-Z0-9-]+'', ''-'')|lower }}{{ threescale_cicd_default_production_suffix }}.{{ threescale_cicd_wildcard_domain }}'
when: 'threescale_cicd_wildcard_domain is defined'
- name: Prefix the system_name with the environment
set_fact:
threescale_cicd_api_system_name: '{{ threescale_cicd_api_system_name_prefix }}{{ threescale_cicd_api_system_name }}'
- name: Append the full version to the API title
set_fact:
threescale_cicd_api_name: '{{ threescale_cicd_api_name }} (v{{ threescale_cicd_api_version }})'
when: 'threescale_cicd_api_environment_name is not defined'
- name: Append the full version and the environment to the API title
set_fact:
threescale_cicd_api_name: '{{ threescale_cicd_api_name }} ({{ threescale_cicd_api_environment_name|upper }}, v{{ threescale_cicd_api_version }})'
when: 'threescale_cicd_api_environment_name is defined'
- name: Extract the security definitions and requirements from OpenAPI
set_fact:
threescale_cicd_api_security_requirements: '{{ threescale_cicd_openapi_file_content.security|default([]) }}'
threescale_cicd_api_security_definitions: '{{ threescale_cicd_openapi_file_content.securityDefinitions|default({}) }}'
- name: Make sure there is one and exactly one security requirement - name: Make sure there is one and exactly one security requirement
assert: assert:
that: that:
- 'threescale_cicd_api_security_requirements|length == 1' - 'threescale_cicd_api_security_requirements|length == 1'
msg: 'You have {{ threescale_cicd_api_security_requirements|length }} global security requirements. There must be one and only one security requirement.' msg: 'You have {{ threescale_cicd_api_security_requirements|length }} global security requirements. There must be one and only one security requirement.'
- name: Find the security requirement to use
set_fact:
threescale_cicd_api_security_scheme_name: '{{ threescale_cicd_api_security_requirements[0].keys()[0] }}'
- name: Make sure the requested security definition exists
assert:
that:
- 'threescale_cicd_api_security_scheme_name in threescale_cicd_api_security_definitions'
- name: Find the security definition to use
set_fact:
threescale_cicd_api_security_scheme: '{{ threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme_name] }}'
- name: Make sure the security scheme is consistent with 3scale - name: Make sure the security scheme is consistent with 3scale
assert: assert:
that: that:
- 'threescale_cicd_api_security_scheme.type == ''apiKey'' or (threescale_cicd_api_security_scheme.type == ''oauth2'' and threescale_cicd_sso_issuer_endpoint is defined)' - '''type'' in threescale_cicd_api_security_scheme and threescale_cicd_api_security_scheme.type == ''apiKey'' or (threescale_cicd_api_security_scheme.type == ''oauth2'' and threescale_cicd_sso_issuer_endpoint is defined)'
msg: |-
- name: Find the correct backend_version to use The embedded security definition {{ threescale_cicd_api_security_scheme_name }} is not compatible with 3scale.
set_fact: Please make sure you chose an "apiKey" or "oauth2" scheme.
threescale_cicd_api_backend_version: '1' Also, if you chose "oauth2", you will need to pass the threescale_cicd_sso_issuer_endpoint extra variable.
when: 'threescale_cicd_api_security_scheme.type == ''apiKey''' The security definition you chose: {{ threescale_cicd_api_security_scheme|to_nice_json }}
- name: Find the correct backend_version to use
set_fact:
threescale_cicd_api_backend_version: 'oidc'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- name: Extract the backend hostname from OpenAPI
set_fact:
threescale_cicd_api_backend_hostname: '{{ threescale_cicd_openapi_file_content.host }}'
when: 'threescale_cicd_api_backend_hostname is not defined and ''host'' in threescale_cicd_openapi_file_content'
- name: Extract the backend scheme from OpenAPI
set_fact:
threescale_cicd_api_backend_scheme: '{{ threescale_cicd_openapi_file_content.schemes|default(["http"])|first }}'
when: 'threescale_cicd_api_backend_scheme is not defined'
- name: Compute the private base url from the OpenAPI file
set_fact:
threescale_cicd_private_base_url: '{{ threescale_cicd_api_backend_scheme ~ ''://'' ~ threescale_cicd_api_backend_hostname }}'
when: threescale_cicd_api_backend_hostname is defined and threescale_cicd_private_base_url is not defined
- assert: - assert:
that: that:
- 'threescale_cicd_private_base_url is defined' - 'threescale_cicd_private_base_url is defined'
msg: 'Either the private base url or the tuple backend hostname/scheme must be declared as extra variables (either threescale_cicd_private_base_url or threescale_cicd_api_backend_scheme / threescale_cicd_api_backend_hostname)' msg: 'Either the private base url or the tuple backend hostname/scheme must be declared as extra variables (either threescale_cicd_private_base_url or threescale_cicd_api_backend_scheme / threescale_cicd_api_backend_hostname)'
- name: Find the smoke-test flagged operation
set_fact:
threescale_cicd_openapi_smoketest_operation: '{{ threescale_cicd_openapi_file_content|json_query(''paths.*.get[? "x-threescale-smoketests-operation" ].operationId|[0]'') }}'
when: 'threescale_cicd_openapi_smoketest_operation is not defined'
- assert: - assert:
that: that:
# Operation must exists # Operation must exists
@ -177,21 +36,7 @@
# Must NOT have a placeholder in the path # Must NOT have a placeholder in the path
- 'threescale_cicd_api_operations[threescale_cicd_openapi_smoketest_operation].path.find("{") == -1' - 'threescale_cicd_api_operations[threescale_cicd_openapi_smoketest_operation].path.find("{") == -1'
msg: "The smoketest operation {{ threescale_cicd_openapi_smoketest_operation }} must be a GET and cannot have a placeholder in its path." msg: "The smoketest operation {{ threescale_cicd_openapi_smoketest_operation }} must be a GET and cannot have a placeholder in its path."
when: 'threescale_cicd_openapi_smoketest_operation is defined and threescale_cicd_openapi_smoketest_operation|length > 0' when: 'threescale_cicd_openapi_smoketest_operation|length > 0'
- set_fact:
threescale_cicd_openapi_smoketest_operation: '{{ threescale_cicd_openapi_smoketest_operation|regex_replace(''[^0-9a-zA-Z_]+'', ''_'') }}'
when: 'threescale_cicd_openapi_smoketest_operation is defined and threescale_cicd_openapi_smoketest_operation|length > 0'
- set_fact:
threescale_cicd_openapi_smoketest_path: '{{ threescale_cicd_api_basepath }}{{ threescale_cicd_api_operations[threescale_cicd_openapi_smoketest_operation].path }}'
when: 'threescale_cicd_openapi_smoketest_operation is defined and threescale_cicd_openapi_smoketest_operation|length > 0'
- name: Compute the service system_name
set_fact:
threescale_cicd_api_system_name: '{{ threescale_cicd_api_environment_name ~ "_" ~ threescale_cicd_api_system_name }}'
when: 'threescale_cicd_api_environment_name is defined'
- debug: - debug:
msg: "Will work on service with system_name = {{ threescale_cicd_api_system_name }}" msg: "Will work on service with system_name = {{ threescale_cicd_api_system_name }}"

7
tasks/steps/requirements.yml

@ -10,6 +10,13 @@
- threescale_cicd_access_token that contains an Access Token with Read/Write privileges on the 3scale Account Management API. This variable is usually set in your inventory file. - threescale_cicd_access_token that contains an Access Token with Read/Write privileges on the 3scale Account Management API. This variable is usually set in your inventory file.
- threescale_cicd_openapi_file that is the path to the OpenAPI file you want to deploy in 3scale. This variable is usually passed as an extra variable (-e threescale_cicd_openapi_file=...) - threescale_cicd_openapi_file that is the path to the OpenAPI file you want to deploy in 3scale. This variable is usually passed as an extra variable (-e threescale_cicd_openapi_file=...)
- name: Make sure the OpenAPI File Format is YAML or JSON
assert:
that:
- threescale_cicd_openapi_file_format|upper == 'JSON' or threescale_cicd_openapi_file_format|upper == 'YAML'
msg: |-
The threescale_cicd_openapi_file_format parameter needs to be either 'JSON' or 'YAML'
- name: Verify that Ansible version is >= 2.4 - name: Verify that Ansible version is >= 2.4
assert: assert:
that: "ansible_version.full is version_compare('2.4', '>=')" that: "ansible_version.full is version_compare('2.4', '>=')"

46
tasks/steps/variables_from_inventory.yml

@ -1,26 +1,28 @@
--- ---
- name: Set the threescale_cicd_sso_issuer_endpoint variable from the inventory - name: Abort on deprecated feature -> the "sso" inventory group
set_fact: fail:
threescale_cicd_sso_issuer_endpoint: '{{ (hostvars[groups[''sso''][0]].scheme|default(''https'')) ~ ''://'' ~ hostvars[groups[''sso''][0]].client_id ~ '':'' ~ hostvars[groups[''sso''][0]].client_secret ~ ''@'' ~ groups[''sso''][0] ~ ''/auth/realms/'' ~ hostvars[groups[''sso''][0]].realm }}' msg: >
when: 'threescale_cicd_sso_issuer_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0' You are currently using a deprecated feature (the 'sso' group in your inventory).
Please replace it with the 'threescale_cicd_sso_issuer_endpoint' variable.
Alternatively, you can also bypass this warning by setting the 'threescale_cicd_deprecated_features'
extra variable to 'true'.
when: 'threescale_cicd_sso_issuer_endpoint|default("")|length > 0 and ''sso'' in groups and groups[''sso''] > 0 and threescale_cicd_api_backend_version == ''oidc'' and not threescale_cicd_deprecated_features|default(false)|bool'
- name: Set the threescale_cicd_sso_realm_endpoint variable from the threescale_cicd_sso_issuer_endpoint - name: Abort on deprecated feature -> the "apicast-sandbox" inventory group
set_fact: fail:
threescale_cicd_sso_realm_endpoint: '{{ (threescale_cicd_sso_issuer_endpoint|urlsplit(''scheme'')) ~ ''://'' ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''hostname'')) ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''path'')) }}' msg: >
when: 'threescale_cicd_sso_realm_endpoint is not defined and threescale_cicd_sso_issuer_endpoint is defined' You are currently using a deprecated feature (the 'apicast-sandbox' group in your inventory).
Please replace it with the 'threescale_cicd_apicast_sandbox_endpoint' variable.
Alternatively, you can also bypass this warning by setting the 'threescale_cicd_deprecated_features'
extra variable to 'true'.
when: 'threescale_cicd_apicast_sandbox_endpoint|default("")|length > 0 and ''apicast-sandbox'' in groups and groups[''apicast-sandbox''] > 0 and not threescale_cicd_deprecated_features|default(false)|bool'
- name: Set the threescale_cicd_sso_admin_endpoint variable from the threescale_cicd_sso_realm_endpoint - name: Abort on deprecated feature -> the "apicast-production" inventory group
set_fact: fail:
threescale_cicd_sso_admin_endpoint: '{{ threescale_cicd_sso_realm_endpoint|replace(''/auth/realms/'', ''/auth/admin/realms/'') }}' msg: >
when: 'threescale_cicd_sso_admin_endpoint is not defined and threescale_cicd_sso_realm_endpoint is defined' You are currently using a deprecated feature (the 'apicast-production' group in your inventory).
Please replace it with the 'threescale_cicd_apicast_production_endpoint' variable.
- name: Set the threescale_cicd_apicast_sandbox_endpoint variable from the inventory Alternatively, you can also bypass this warning by setting the 'threescale_cicd_deprecated_features'
set_fact: extra variable to 'true'.
threescale_cicd_apicast_sandbox_endpoint: '{{ (hostvars[groups[''apicast-sandbox''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''apicast-sandbox''][0] }}' when: 'threescale_cicd_apicast_production_endpoint|default("")|length > 0 and ''apicast-production'' in groups and groups[''apicast-production''] > 0 and not threescale_cicd_deprecated_features|default(false)|bool'
when: 'threescale_cicd_apicast_sandbox_endpoint is not defined and ''apicast-sandbox'' in groups and groups[''apicast-sandbox''] > 0'
- name: Set the threescale_cicd_apicast_production_endpoint variable from the inventory
set_fact:
threescale_cicd_apicast_production_endpoint: '{{ (hostvars[groups[''apicast-production''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''apicast-production''][0] }}'
when: 'threescale_cicd_apicast_production_endpoint is not defined and ''apicast-production'' in groups and groups[''apicast-production''] > 0'

7
templates/api-calls/create_service.j2

@ -1,8 +1,13 @@
{% if threescale_cicd_apicast_sandbox_endpoint|default("")|length > 0 or threescale_cicd_apicast_production_endpoint|default("")|length > 0 %}
{% set deployment_type = "self_managed" %}
{% else %}
{% set deployment_type = "hosted" %}
{% endif %}
{% {%
set payload = [ set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode, 'access_token=' ~ threescale_cicd_access_token|urlencode,
'name=' ~ threescale_cicd_api_name|urlencode, 'name=' ~ threescale_cicd_api_name|urlencode,
'deployment_option=' ~ threescale_cicd_api_deployment_type|urlencode, 'deployment_option=' ~ deployment_type|urlencode,
'system_name=' ~ threescale_cicd_api_system_name|urlencode, 'system_name=' ~ threescale_cicd_api_system_name|urlencode,
'backend_version=' ~ threescale_cicd_api_backend_version|urlencode 'backend_version=' ~ threescale_cicd_api_backend_version|urlencode
] ]

4
templates/api-calls/smoke-test/url.j2

@ -1,8 +1,8 @@
{%- if threescale_cicd_smoke_test_env == "staging" -%} {%- if threescale_cicd_smoke_test_env == "staging" -%}
{{ threescale_cicd_apicast_sandbox_endpoint }} {{ threescale_cicd_apicast_discovered_sandbox_endpoint }}
{%- endif -%} {%- endif -%}
{%- if threescale_cicd_smoke_test_env == "production" -%} {%- if threescale_cicd_smoke_test_env == "production" -%}
{{ threescale_cicd_apicast_production_endpoint }} {{ threescale_cicd_apicast_discovered_production_endpoint }}
{%- endif -%} {%- endif -%}
{{ threescale_cicd_openapi_smoketest_path }} {{ threescale_cicd_openapi_smoketest_path }}
{%- if threescale_cicd_api_security_scheme.type == "apiKey" and threescale_cicd_api_credentials_location == "query" -%} {%- if threescale_cicd_api_security_scheme.type == "apiKey" and threescale_cicd_api_credentials_location == "query" -%}

4
templates/api-calls/update_proxy.j2

@ -11,10 +11,10 @@
{% if threescale_cicd_api_security_scheme.type == 'oauth2' %} {% if threescale_cicd_api_security_scheme.type == 'oauth2' %}
{% do payload.append('oidc_issuer_endpoint=' ~ threescale_cicd_sso_issuer_endpoint|urlencode) %} {% do payload.append('oidc_issuer_endpoint=' ~ threescale_cicd_sso_issuer_endpoint|urlencode) %}
{% endif %} {% endif %}
{% if threescale_cicd_apicast_sandbox_endpoint is defined %} {% if threescale_cicd_apicast_sandbox_endpoint|default("")|length > 0 %}
{% do payload.append('sandbox_endpoint=' ~ threescale_cicd_apicast_sandbox_endpoint|urlencode) %} {% do payload.append('sandbox_endpoint=' ~ threescale_cicd_apicast_sandbox_endpoint|urlencode) %}
{% endif %} {% endif %}
{% if threescale_cicd_apicast_production_endpoint is defined %} {% if threescale_cicd_apicast_production_endpoint|default("")|length > 0 %}
{% do payload.append('endpoint=' ~ threescale_cicd_apicast_production_endpoint|urlencode) %} {% do payload.append('endpoint=' ~ threescale_cicd_apicast_production_endpoint|urlencode) %}
{% endif %} {% endif %}
{{ payload|join("&") }} {{ payload|join("&") }}

5
templates/openapi/apicast_production_endpoint.j2

@ -0,0 +1,5 @@
{%- if threescale_cicd_wildcard_domain is defined -%}
{{ threescale_cicd_default_apicast_scheme }}://{{ (threescale_cicd_api_base_system_name ~ "-" ~ threescale_cicd_api_version_major)|regex_replace('[^a-zA-Z0-9-]+', '-')|lower }}{{ threescale_cicd_default_production_suffix }}.{{ threescale_cicd_wildcard_domain }}
{%- elif 'apicast-production' in groups and groups['apicast-production'] > 0 -%}
{{ (hostvars[groups['apicast-production'][0]].scheme|default('https')) ~ '://' ~ groups['apicast-production'][0] }}
{%- endif -%}

5
templates/openapi/apicast_sandbox_endpoint.j2

@ -0,0 +1,5 @@
{%- if threescale_cicd_wildcard_domain is defined -%}
{{ threescale_cicd_default_apicast_scheme }}://{{ (threescale_cicd_api_base_system_name ~ "-" ~ threescale_cicd_api_version_major)|regex_replace('[^a-zA-Z0-9-]+', '-')|lower }}{{ threescale_cicd_default_staging_suffix }}.{{ threescale_cicd_wildcard_domain }}
{%- elif 'apicast-sandbox' in groups and groups['apicast-sandbox'] > 0 -%}
{{ (hostvars[groups['apicast-sandbox'][0]].scheme|default('https')) ~ '://' ~ groups['apicast-sandbox'][0] }}
{%- endif -%}

6
templates/openapi/generate_base_system_name.j2

@ -0,0 +1,6 @@
{% if 'x-threescale-system-name' in threescale_cicd_openapi_file_content.info %}
{% set extracted_system_name = threescale_cicd_openapi_file_content.info['x-threescale-system-name']|regex_replace('[^a-zA-Z0-9_]+', '_')|lower %}
{% else %}
{% set extracted_system_name = threescale_cicd_openapi_file_content.info['title']|default('api')|regex_replace('[^a-zA-Z0-9_]+', '_')|lower %}
{% endif %}
{{ extracted_system_name }}

4
templates/openapi/generate_final_system_name.j2

@ -0,0 +1,4 @@
{%- if threescale_cicd_api_environment_name is defined -%}
{%- set system_name_prefix = threescale_cicd_api_environment_name|default("")|regex_replace('[^a-zA-Z0-9_]+', '_') ~ "_" -%}
{%- endif -%}
{{ system_name_prefix|default("") }}{{ threescale_cicd_api_base_system_name }}_{{ threescale_cicd_api_version_major|regex_replace('[^a-zA-Z0-9_]+', '_') }}

26
templates/openapi/openapi_operations.j2

@ -0,0 +1,26 @@
{% set operations = {} -%}
{% if 'paths' in threescale_cicd_openapi_file_content -%}
{% for path, verbs in threescale_cicd_openapi_file_content['paths'].items() -%}
{% if path.startswith('/') -%}
{% for verb, method_description in verbs.items() -%}
{% if verb != '$ref' and verb != 'parameters' -%}
{% if 'operationId' in method_description -%}
{% set operation_id = method_description['operationId'] -%}
{% else -%}
{% set operation_id = verb.upper() + path -%}
{% endif -%}
{% set operation_id = operation_id|regex_replace('[^0-9a-zA-Z_]+', '_') -%}
{% set operation = { operation_id: { 'path': path, 'verb': verb } } -%}
{% if 'summary' in method_description -%}
{% do operation[operation_id].update({ 'friendly_name': method_description.summary }) -%}
{% endif -%}
{% if 'description' in method_description -%}
{% do operation[operation_id].update({ 'description': method_description.description }) -%}
{% endif -%}
{% do operations.update(operation) -%}
{% endif -%}
{% endfor -%}
{% endif -%}
{% endfor -%}
{% endif -%}
{{ operations }}

11
templates/openapi/private_base_url.j2

@ -0,0 +1,11 @@
{%- if threescale_cicd_api_backend_hostname is not defined and 'host' in threescale_cicd_openapi_file_content -%}
{%- set backend_hostname = threescale_cicd_openapi_file_content.host -%}
{%- else -%}
{%- set backend_hostname = threescale_cicd_api_backend_hostname -%}
{%- endif -%}
{%- if threescale_cicd_api_backend_scheme is not defined -%}
{%- set backend_scheme = threescale_cicd_openapi_file_content.schemes|default(["http"])|first -%}
{%- else -%}
{%- set backend_scheme = threescale_cicd_api_backend_scheme -%}
{%- endif -%}
{{ backend_scheme }}://{{ backend_hostname }}

5
templates/openapi/service_name.j2

@ -0,0 +1,5 @@
{%- if threescale_cicd_api_environment_name is defined -%}
{{ threescale_cicd_api_default_name }} ({{ threescale_cicd_api_environment_name|upper }}, v{{ threescale_cicd_api_version }})
{%- else -%}
{{ threescale_cicd_api_default_name }} (v{{ threescale_cicd_api_version }})
{%- endif -%}

3
templates/openapi/sso_issuer_endpoint.j2

@ -0,0 +1,3 @@
{%- if 'sso' in groups and groups['sso'] > 0 -%}
{{ (hostvars[groups['sso'][0]].scheme|default('https')) ~ '://' ~ hostvars[groups['sso'][0]].client_id ~ ':' ~ hostvars[groups['sso'][0]].client_secret ~ '@' ~ groups['sso'][0] ~ '/auth/realms/' ~ hostvars[groups['sso'][0]].realm }}
{%- endif -%}

4
templates/rewritten_openapi.j2

@ -11,8 +11,8 @@
{# Update the security definitions #} {# Update the security definitions #}
{% do new_openapi.update({ "securityDefinitions": security_definitions }) %} {% do new_openapi.update({ "securityDefinitions": security_definitions }) %}
{# Update the "schemes" and "hostname" fields with the public apicast production URL #} {# Update the "schemes" and "hostname" fields with the public apicast production URL #}
{% set apicast_production_scheme = threescale_cicd_apicast_production_endpoint|urlsplit('scheme') %} {% set apicast_production_scheme = threescale_cicd_apicast_discovered_production_endpoint|urlsplit('scheme') %}
{% set apicast_production_hostname = threescale_cicd_apicast_production_endpoint|urlsplit('hostname') %} {% set apicast_production_hostname = threescale_cicd_apicast_discovered_production_endpoint|urlsplit('hostname') %}
{% do new_openapi.update({ {% do new_openapi.update({
"schemes": [ apicast_production_scheme ], "schemes": [ apicast_production_scheme ],
"host": apicast_production_hostname "host": apicast_production_hostname

16
tests/3scale-saas-with-hosted-apicast-apikey.yml

@ -8,10 +8,14 @@
threescale_cicd_openapi_file_format: 'JSON' threescale_cicd_openapi_file_format: 'JSON'
threescale_cicd_api_backend_hostname: echo-api.3scale.net threescale_cicd_api_backend_hostname: echo-api.3scale.net
threescale_cicd_openapi_smoketest_operation: GET_beer threescale_cicd_openapi_smoketest_operation: GET_beer
roles: tasks:
# Test first deployment # Test a first deployment
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 1 } } - import_role:
name: 'nmasse-itix.threescale-cicd'
# Verify idempotence # Verify idempotence
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 2 } } - import_role:
post_tasks: name: 'nmasse-itix.threescale-cicd'
- import_tasks: 'cleanup.yaml' # Delete the service
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'

45
tests/3scale-saas-with-hosted-apicast-multi-environment.yml

@ -0,0 +1,45 @@
---
- name: Deploy the Beer Catalog API to a 3scale SaaS instance in multi environment
hosts: threescale
gather_facts: no
vars:
threescale_cicd_openapi_file: '{{ playbook_dir }}/api/beer-catalog-api.json'
threescale_cicd_openapi_file_format: 'JSON'
threescale_cicd_api_backend_hostname: echo-api.3scale.net
threescale_cicd_openapi_smoketest_operation: GET_beer
threescale_cicd_api_base_system_name: beer_catalog
tasks:
# Deploy in DEV
- import_role:
name: 'nmasse-itix.threescale-cicd'
vars:
threescale_cicd_api_environment_name: dev
# Deploy in TEST
- import_role:
name: 'nmasse-itix.threescale-cicd'
vars:
threescale_cicd_api_environment_name: test
# Deploy in PROD
- import_role:
name: 'nmasse-itix.threescale-cicd'
vars:
threescale_cicd_api_environment_name: prod
# Cleanup the DEV
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'
vars:
threescale_cicd_api_environment_name: dev
# Cleanup the TEST
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'
vars:
threescale_cicd_api_environment_name: test
# Cleanup the PROD
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'
vars:
threescale_cicd_api_environment_name: prod

16
tests/3scale-saas-with-hosted-apicast-oidc.yml

@ -5,10 +5,14 @@
gather_facts: no gather_facts: no
vars: vars:
threescale_cicd_openapi_file: '{{ playbook_dir }}/api/echo-api-oidc.yaml' threescale_cicd_openapi_file: '{{ playbook_dir }}/api/echo-api-oidc.yaml'
roles: tasks:
# Test first deployment # Test a first deployment
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 1 } } - import_role:
name: 'nmasse-itix.threescale-cicd'
# Verify idempotence # Verify idempotence
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 2 } } - import_role:
post_tasks: name: 'nmasse-itix.threescale-cicd'
- import_tasks: 'cleanup.yaml' # Delete the service
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'

16
tests/3scale-saas-with-hosted-apicast-with-basePath.yml

@ -5,10 +5,14 @@
gather_facts: no gather_facts: no
vars: vars:
threescale_cicd_openapi_file: '{{ playbook_dir }}/api/echo-api-with-basePath.yaml' threescale_cicd_openapi_file: '{{ playbook_dir }}/api/echo-api-with-basePath.yaml'
roles: tasks:
# Test first deployment # Test a first deployment
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 1 } } - import_role:
name: 'nmasse-itix.threescale-cicd'
# Verify idempotence # Verify idempotence
- { role: 'nmasse-itix.threescale-cicd', vars: { 'round': 2 } } - import_role:
post_tasks: name: 'nmasse-itix.threescale-cicd'
- import_tasks: 'cleanup.yaml' # Delete the service
- import_role:
name: 'nmasse-itix.threescale-cicd'
tasks_from: 'cleanup'

10
tests/inventory.j2

@ -6,12 +6,4 @@ ansible_connection=local
[threescale:vars] [threescale:vars]
threescale_cicd_access_token={{ threescale_inventory.threescale_hosted.access_token }} threescale_cicd_access_token={{ threescale_inventory.threescale_hosted.access_token }}
threescale_cicd_sso_issuer_endpoint=https://{{ threescale_inventory.sso.client_id }}:{{ threescale_inventory.sso.client_secret }}@{{ threescale_inventory.sso.host }}/auth/realms/{{ threescale_inventory.sso.realm }}
[sso]
{{ threescale_inventory.sso.host }}
[sso:vars]
realm={{ threescale_inventory.sso.realm }}
client_id={{ threescale_inventory.sso.client_id }}
client_secret={{ threescale_inventory.sso.client_secret }}
scheme=https

29
vars/main.yml

@ -9,6 +9,35 @@ threescale_cicd_metrics_to_delete: '{{ lookup(''template'', ''metrics_to_delete
# The OpenAPI file to be pushed to 3scale as an ActiveDocs # The OpenAPI file to be pushed to 3scale as an ActiveDocs
threescale_cicd_openapi_rewritten: '{{ lookup(''template'', ''rewritten_openapi.j2'') }}' threescale_cicd_openapi_rewritten: '{{ lookup(''template'', ''rewritten_openapi.j2'') }}'
# Compute the Keycloak Realm endpoint from the threescale_cicd_sso_issuer_endpoint
threescale_cicd_sso_realm_endpoint: '{{ (threescale_cicd_sso_issuer_endpoint|urlsplit(''scheme'')) ~ ''://'' ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''hostname'')) ~ (threescale_cicd_sso_issuer_endpoint|urlsplit(''path'')) }}'
# Compute the Keycloak REST Admin Endpoint from the threescale_cicd_sso_realm_endpoint
threescale_cicd_sso_admin_endpoint: '{{ threescale_cicd_sso_realm_endpoint|replace(''/auth/realms/'', ''/auth/admin/realms/'') }}'
##
## OpenAPI Specification File parsing
##
threescale_cicd_openapi_file_content: '{{ lookup(''file'', threescale_cicd_openapi_file)|from_json if threescale_cicd_openapi_file_format|upper == ''JSON'' else lookup(''file'', threescale_cicd_openapi_file)|from_yaml }}'
threescale_cicd_openapi_file_version: '{{ threescale_cicd_openapi_file_content.swagger }}'
threescale_cicd_api_default_name: '{{ threescale_cicd_openapi_file_content.info.title|default("API") }}'
threescale_cicd_api_name: '{{ lookup(''template'', ''openapi/service_name.j2'') }}'
threescale_cicd_api_description: '{{ threescale_cicd_openapi_file_content.info.description|default("") }}'
threescale_cicd_api_version: '{{ threescale_cicd_openapi_file_content.info.version|default("0.0.1") }}'
threescale_cicd_api_basepath: '{{ threescale_cicd_openapi_file_content.basePath|default("") }}'
threescale_cicd_api_operations: '{{ lookup(''template'', ''openapi/openapi_operations.j2'') }}'
threescale_cicd_api_version_components: '{{ threescale_cicd_api_version.split(".") }}'
threescale_cicd_api_version_major: '{{ threescale_cicd_api_version_components|first }}'
threescale_cicd_api_security_requirements: '{{ threescale_cicd_openapi_file_content.security|default([]) }}'
threescale_cicd_api_security_definitions: '{{ threescale_cicd_openapi_file_content.securityDefinitions|default({}) }}'
threescale_cicd_api_security_scheme_name: '{{ threescale_cicd_api_security_requirements[0].keys()[0]|default(''none'') }}'
threescale_cicd_api_security_scheme: '{{ threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme_name] if threescale_cicd_api_security_scheme_name in threescale_cicd_api_security_definitions else {} }}'
threescale_cicd_api_backend_version: '{{ threescale_cicd_backend_version_mapping[threescale_cicd_api_security_scheme.type] }}'
threescale_cicd_backend_version_mapping:
apiKey: '1'
oauth2: 'oidc'
threescale_cicd_openapi_smoketest_path: '{{ threescale_cicd_api_basepath }}{{ threescale_cicd_api_operations[threescale_cicd_openapi_smoketest_operation].path }}'
## ##
## ID Lookup Variables ## ID Lookup Variables
## ##

Loading…
Cancel
Save