Browse Source

See #22: reorganize this role so that it use variables where possible (instead of facts)

pull/24/head
Nicolas Massé 7 years ago
parent
commit
8f8ec50d35
  1. 2
      ansible.cfg
  2. 20
      defaults/main.yml
  3. 23
      tasks/api-calls/create_activedoc.yml
  4. 21
      tasks/api-calls/create_application.yml
  5. 22
      tasks/api-calls/create_application_plan.yml
  6. 19
      tasks/api-calls/create_mapping_rule.yml
  7. 23
      tasks/api-calls/create_method.yml
  8. 24
      tasks/api-calls/create_service.yml
  9. 14
      tasks/api-calls/delete_mapping_rule.yml
  10. 17
      tasks/api-calls/delete_metric.yml
  11. 13
      tasks/api-calls/find_application.yml
  12. 10
      tasks/api-calls/find_first_account.yml
  13. 20
      tasks/api-calls/get_proxy_version.yml
  14. 22
      tasks/api-calls/keycloak/authenticate.yml
  15. 21
      tasks/api-calls/keycloak/patch_client.yml
  16. 18
      tasks/api-calls/keycloak/wait_for_client.yml
  17. 17
      tasks/api-calls/promote_proxy.yml
  18. 20
      tasks/api-calls/smoke_test.yml
  19. 19
      tasks/api-calls/update_activedoc.yml
  20. 21
      tasks/api-calls/update_application.yml
  21. 18
      tasks/api-calls/update_application_plan.yml
  22. 21
      tasks/api-calls/update_mapping_rule.yml
  23. 18
      tasks/api-calls/update_method.yml
  24. 28
      tasks/api-calls/update_proxy.yml
  25. 19
      tasks/api-calls/update_service.yml
  26. 32
      tasks/check_requirements.yml
  27. 113
      tasks/create_activedocs.yml
  28. 38
      tasks/create_application_plans.yml
  29. 89
      tasks/create_default_application.yml
  30. 28
      tasks/create_mapping_rule.yml
  31. 58
      tasks/create_service.yml
  32. 25
      tasks/delete_unused_metrics.yml
  33. 142
      tasks/main.yml
  34. 65
      tasks/patch_default_application_for_oauth.yml
  35. 42
      tasks/promote.yml
  36. 59
      tasks/smoke_tests.yml
  37. 9
      tasks/smoke_tests_apikey.yml
  38. 36
      tasks/smoke_tests_oauth.yml
  39. 9
      tasks/steps/activedoc.yml
  40. 8
      tasks/steps/application_plan.yml
  41. 6
      tasks/steps/application_plans.yml
  42. 6
      tasks/steps/cleanup_metrics.yml
  43. 33
      tasks/steps/default_application.yml
  44. 47
      tasks/steps/discover.yml
  45. 25
      tasks/steps/mapping_rules.yml
  46. 7
      tasks/steps/method.yml
  47. 16
      tasks/steps/methods.yml
  48. 6
      tasks/steps/promote.yml
  49. 3
      tasks/steps/proxy.yml
  50. 9
      tasks/steps/read_openapi.yml
  51. 57
      tasks/steps/requirements.yml
  52. 7
      tasks/steps/service.yml
  53. 14
      tasks/steps/smoke_test.yml
  54. 26
      tasks/steps/variables_from_inventory.yml
  55. 30
      tasks/update_mapping_rule.yml
  56. 59
      tasks/update_mapping_rules.yml
  57. 47
      tasks/update_method.yml
  58. 20
      tasks/update_metrics.yml
  59. 23
      tasks/update_proxy.yml
  60. 11
      templates/api-calls/create_activedoc.j2
  61. 15
      templates/api-calls/create_application.j2
  62. 9
      templates/api-calls/create_application_plan.j2
  63. 10
      templates/api-calls/create_mapping_rule.j2
  64. 10
      templates/api-calls/create_method.j2
  65. 10
      templates/api-calls/create_service.j2
  66. 7
      templates/api-calls/find_application.j2
  67. 5
      templates/api-calls/keycloak/authenticate.j2
  68. 1
      templates/api-calls/keycloak/patch_client.j2
  69. 1
      templates/api-calls/promote_proxy.j2
  70. 8
      templates/api-calls/smoke-test/headers.j2
  71. 10
      templates/api-calls/smoke-test/url.j2
  72. 1
      templates/api-calls/update_activedoc.j2
  73. 1
      templates/api-calls/update_application.j2
  74. 1
      templates/api-calls/update_application_plan.j2
  75. 1
      templates/api-calls/update_mapping_rule.j2
  76. 1
      templates/api-calls/update_method.j2
  77. 20
      templates/api-calls/update_proxy.j2
  78. 1
      templates/api-calls/update_service.j2
  79. 5
      templates/existing_mapping_rules.j2
  80. 7
      templates/metrics_to_delete.j2
  81. 22
      templates/rewritten_openapi.j2
  82. 5
      templates/wanted_mapping_rules.j2
  83. 63
      vars/main.yml

2
ansible.cfg

@ -0,0 +1,2 @@
[defaults]
jinja2_extensions = jinja2.ext.do

20
defaults/main.yml

@ -3,8 +3,6 @@ threescale_cicd_openapi_file_format: YAML
threescale_cicd_delay: 10
threescale_cicd_retries: 50
threescale_cicd_throttling: 2
threescale_cicd_default_application_name: 'Ansible smoke-tests default application'
threescale_cicd_default_application_description: 'This app is used to run smoke tests during the deployment phase. It will be automatically recreated if you delete it.'
threescale_cicd_staging_environment_name: sandbox
threescale_cicd_production_environment_name: production
threescale_cicd_default_staging_suffix: -staging
@ -18,3 +16,21 @@ threescale_cicd_application_plans:
default: false
state: hidden
name: Ansible Test Plan
# Specifies that APIcast is self managed (if a public staging and/or
# production URL is given), or hosted
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'' }}'
##
## Default Application (used for Smoke Tests)
##
threescale_cicd_default_application_name: 'Ansible smoke-tests default application'
threescale_cicd_default_application_description: 'This app is used to run smoke tests during the deployment phase. It will be automatically recreated if you delete it.'
# The application plan to pick for the default application (the one used for
# smoke tests)
threescale_cicd_default_application_plan: '{{ (threescale_cicd_application_plans|first).system_name }}'
# Compute the default application's appid. By default, we are using a combination
# 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'') }}'

23
tasks/api-calls/create_activedoc.yml

@ -0,0 +1,23 @@
---
- debug:
var: threescale_cicd_create_activedoc_payload
verbosity: 1
- name: Create the ActiveDocs
uri:
url: https://{{ inventory_hostname }}/admin/api/active_docs.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_activedoc_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_existing_activedocs|union([ threescale_cicd_tmpresponse.json.api_doc.system_name ]) }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_existing_activedocs_details|union([ { ''id'': threescale_cicd_tmpresponse.json.api_doc.id, ''system_name'': threescale_cicd_tmpresponse.json.api_doc.system_name } ]) }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

21
tasks/api-calls/create_application.yml

@ -0,0 +1,21 @@
---
- debug:
var: threescale_cicd_create_application_payload
verbosity: 1
- name: Create the application
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts/{{ threescale_cicd_default_account_id }}/applications.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_application_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_default_application_details: '{{ threescale_cicd_tmpresponse.json.application }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

22
tasks/api-calls/create_application_plan.yml

@ -0,0 +1,22 @@
---
- debug:
var: threescale_cicd_create_application_plan_payload
verbosity: 1
- name: Create the application plan
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_application_plan_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_existing_application_plans: '{{ threescale_cicd_existing_application_plans|union([ threescale_cicd_application_plan.system_name ]) }}'
threescale_cicd_existing_application_plans_details: '{{ threescale_cicd_existing_application_plans_details|union([{ "system_name": threescale_cicd_application_plan.system_name, "id": threescale_cicd_tmpresponse.json.application_plan.id }]) }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

19
tasks/api-calls/create_mapping_rule.yml

@ -0,0 +1,19 @@
---
- debug:
var: threescale_cicd_create_mapping_rule_payload
verbosity: 1
- name: Create the mapping rule
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_mapping_rule_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

23
tasks/api-calls/create_method.yml

@ -0,0 +1,23 @@
---
- debug:
var: threescale_cicd_create_method_payload
verbosity: 1
- name: Create the method
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_method_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
- set_fact:
threescale_cicd_existing_metrics: '{{ threescale_cicd_existing_metrics|union([ threescale_cicd_api_operation.key ]) }}'
threescale_cicd_existing_metrics_details: '{{ threescale_cicd_existing_metrics_details|union([ { "system_name": threescale_cicd_api_operation.key, "id": threescale_cicd_tmpresponse.json|json_query("method.id") } ]) }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

24
tasks/api-calls/create_service.yml

@ -0,0 +1,24 @@
---
- debug:
var: threescale_cicd_create_service_payload
verbosity: 1
- name: Create the service
uri:
url: https://{{ inventory_hostname }}/admin/api/services.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_create_service_payload }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_existing_services|union([ threescale_cicd_tmpresponse.json.service.system_name ]) }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_existing_services_details|union([ { ''id'': threescale_cicd_tmpresponse.json.service.id, ''system_name'': threescale_cicd_tmpresponse.json.service.system_name } ]) }}'
cacheable: true
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

14
tasks/api-calls/delete_mapping_rule.yml

@ -0,0 +1,14 @@
---
- name: Delete the unused mapping rules
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules/{{ threescale_cicd_existing_mapping_rules[threescale_cicd_mapping_rule] }}.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
method: DELETE
status_code: 200,404
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

17
tasks/api-calls/delete_metric.yml

@ -0,0 +1,17 @@
---
- debug:
msg: "Deleting unused metric {{ threescale_cicd_metric.system_name }}..."
- name: Delete the metric
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods/{{ threescale_cicd_metric.id }}.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
method: DELETE
status_code: 200,404
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

13
tasks/api-calls/find_application.yml

@ -0,0 +1,13 @@
---
- name: Check if the default application exists
uri:
url: 'https://{{ inventory_hostname }}/admin/api/applications/find.json?{{ threescale_cicd_find_application_payload }}'
validate_certs: no
method: GET
status_code: 200,404
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_default_application_id: '{{ threescale_cicd_tmpresponse.json.application.id }}'
when: 'threescale_cicd_tmpresponse.status == 200'

10
tasks/api-calls/find_first_account.yml

@ -0,0 +1,10 @@
---
- name: Get the default (first) account
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts.json?access_token={{ threescale_cicd_access_token|urlencode }}&state=approved&page=1&per_page=1
validate_certs: no
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_default_account_id: '{{ threescale_cicd_tmpresponse.json.accounts[0].account.id }}'

20
tasks/api-calls/get_proxy_version.yml

@ -0,0 +1,20 @@
---
- name: Get the version of the staging proxy definition
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_staging_environment_name }}/latest.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_staging_proxy_version: '{{ threescale_cicd_tmpresponse.json.proxy_config.version }}'
- name: Get the version of the production proxy definition
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_production_environment_name }}/latest.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
status_code: 200,404
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_production_proxy_version: '{{ threescale_cicd_tmpresponse.json.proxy_config.version if threescale_cicd_tmpresponse.status == 200 else ''NONE'' }}'

22
tasks/api-calls/keycloak/authenticate.yml

@ -0,0 +1,22 @@
---
- debug:
var: threescale_cicd_authenticate_to_keycloak_payload
verbosity: 1
- name: Authenticate to RH-SSO
uri:
url: '{{ threescale_cicd_sso_realm_endpoint }}/protocol/openid-connect/token'
body: '{{ threescale_cicd_authenticate_to_keycloak_payload }}'
method: POST
validate_certs: no
return_content: yes
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
# temporary fix for https://github.com/ansible/ansible/issues/28078
until: 'threescale_cicd_tmpresponse is success'
- name: Extract the access_token
set_fact:
threescale_cicd_keycloak_access_token: '{{ threescale_cicd_tmpresponse.json |json_query("access_token") }}'

21
tasks/api-calls/keycloak/patch_client.yml

@ -0,0 +1,21 @@
---
- debug:
var: threescale_cicd_patch_keycloak_client_payload
verbosity: 1
- name: Patch the client in RH-SSO to support the "client_credentials" and "password" grant_type.
uri:
url: '{{ threescale_cicd_sso_admin_endpoint }}/clients/{{ threescale_cicd_default_application_sso_id|urlencode }}'
method: PUT
validate_certs: no
body: '{{ threescale_cicd_patch_keycloak_client_payload }}'
body_format: json
status_code: '200,204'
headers:
Authorization: 'Bearer {{ threescale_cicd_keycloak_access_token }}'
Content-Type: 'application/json'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

18
tasks/api-calls/keycloak/wait_for_client.yml

@ -0,0 +1,18 @@
---
- name: Wait for the new client to appear in RH-SSO
uri:
url: '{{ threescale_cicd_sso_admin_endpoint }}/clients?clientId={{ threescale_cicd_default_application_appid|urlencode }}'
method: GET
validate_certs: no
return_content: yes
headers:
Authorization: 'Bearer {{ threescale_cicd_keycloak_access_token }}'
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
until: 'threescale_cicd_tmpresponse is success and threescale_cicd_tmpresponse.json|length > 0'
- set_fact:
threescale_cicd_default_application_sso_id: '{{ threescale_cicd_tmpresponse.json[0].id }}'
threescale_cicd_default_application_sso_body: '{{ threescale_cicd_tmpresponse.json[0] }}'

17
tasks/api-calls/promote_proxy.yml

@ -0,0 +1,17 @@
---
- debug:
var: threescale_cicd_promote_proxy_payload
verbosity: 1
- name: Promote to production
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_staging_environment_name }}/{{ threescale_cicd_staging_proxy_version }}/promote.json'
body: '{{ threescale_cicd_promote_proxy_payload }}'
status_code: 201
validate_certs: no
method: POST
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

20
tasks/api-calls/smoke_test.yml

@ -0,0 +1,20 @@
---
- debug:
var: threescale_cicd_smoke_test_headers
verbosity: 1
- debug:
msg: "Starting a smoke test on '{{ threescale_cicd_smoke_test_url }}'..."
- name: Running smoke tests !
uri:
url: '{{ threescale_cicd_smoke_test_url }}'
headers: '{{ threescale_cicd_smoke_test_headers }}'
validate_certs: no
method: GET
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
# temporary fix for https://github.com/ansible/ansible/issues/28078
until: 'threescale_cicd_tmpresponse is success'

19
tasks/api-calls/update_activedoc.yml

@ -0,0 +1,19 @@
---
- debug:
var: threescale_cicd_update_activedoc_payload
verbosity: 1
- name: Update the ActiveDocs
uri:
url: 'https://{{ inventory_hostname }}/admin/api/active_docs/{{ threescale_cicd_api_activedocs_id }}.json'
validate_certs: no
method: PUT
body: '{{ threescale_cicd_update_activedoc_payload }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

21
tasks/api-calls/update_application.yml

@ -0,0 +1,21 @@
---
- debug:
var: threescale_cicd_update_application_payload
verbosity: 1
- name: Update the application
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts/{{ threescale_cicd_default_account_id }}/applications/{{ threescale_cicd_default_application_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_update_application_payload }}'
status_code: 200
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_default_application_details: '{{ threescale_cicd_tmpresponse.json.application }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

18
tasks/api-calls/update_application_plan.yml

@ -0,0 +1,18 @@
---
- debug:
var: threescale_cicd_update_application_plan_payload
verbosity: 1
- name: Update the application plan
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans/{{ (threescale_cicd_existing_application_plans_details|selectattr("system_name", "equalto", threescale_cicd_application_plan.system_name)|first).id }}.json'
validate_certs: no
method: PUT
body: '{{ threescale_cicd_update_application_plan_payload }}'
status_code: 200
register: threescale_cicd_tmpresponse
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

21
tasks/api-calls/update_mapping_rule.yml

@ -0,0 +1,21 @@
---
- debug:
var: threescale_cicd_update_mapping_rule_payload
verbosity: 1
- name: Update the mapping rule
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules/{{ threescale_cicd_mapping_rule_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_update_mapping_rule_payload }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
vars:
threescale_cicd_mapping_rule_id: '{{ threescale_cicd_existing_mapping_rules[threescale_cicd_mapping_rule] }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

18
tasks/api-calls/update_method.yml

@ -0,0 +1,18 @@
---
- debug:
var: threescale_cicd_update_method_payload
verbosity: 1
- name: Update the method
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods/{{ (threescale_cicd_existing_metrics_details|selectattr('system_name', 'equalto', threescale_cicd_api_operation.key)|first).id }}.json
validate_certs: no
method: PATCH
body: '{{ threescale_cicd_update_method_payload }}'
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

28
tasks/api-calls/update_proxy.yml

@ -0,0 +1,28 @@
---
- debug:
var: threescale_cicd_update_proxy_payload
verbosity: 1
- name: Update the proxy definition
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy.json
validate_certs: no
method: PATCH
body: '{{ threescale_cicd_update_proxy_payload }}'
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Extract the staging gateway endpoint from the proxy definition
set_fact:
threescale_cicd_apicast_sandbox_endpoint: '{{ threescale_cicd_tmpresponse.json.proxy.sandbox_endpoint }}'
when: "threescale_cicd_apicast_sandbox_endpoint is not defined"
- 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
pause:
seconds: '{{ threescale_cicd_throttling }}'

19
tasks/api-calls/update_service.yml

@ -0,0 +1,19 @@
---
- debug:
var: threescale_cicd_update_service_payload
verbosity: 1
- name: Update the service
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_update_service_payload }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

32
tasks/check_requirements.yml

@ -1,32 +0,0 @@
---
- name: Verify that Ansible version is >= 2.4
assert:
that: "ansible_version.full is version_compare('2.4', '>=')"
msg: This module requires at least Ansible 2.4
- name: Check if jmespath is installed locally
debug: msg={{dummy|json_query('@')}}
register: check_jmespath
ignore_errors: yes
vars:
dummy: Hello World
- name: Check if jinja 2.8 is installed locally
debug: msg={{(dummy|selectattr("id", "equalto", "hello")|first)['value']}}
vars:
dummy:
- id: hello
value: Hello World
register: check_jinja28
ignore_errors: yes
- assert:
that:
- 'check_jmespath is success'
msg: "The JMESPath library is required by this role. Please install the JMESPath library with 'pip install jmespath'."
- assert:
that:
- 'check_jinja28 is success'
msg: "At least Jinja v2.8 is required by this role. Please update Jinja with 'pip install -U Jinja2'."

113
tasks/create_activedocs.yml

@ -1,113 +0,0 @@
---
- name: Retrieve existing ActiveDocs from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/active_docs.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmp_allactivedocs
- set_fact:
threescale_cicd_existing_activedocs: '{{ threescale_cicd_tmp_allactivedocs.json|json_query(''api_docs[*].api_doc.system_name'') }}'
threescale_cicd_existing_activedocs_details: '{{ threescale_cicd_tmp_allactivedocs.json|json_query(''api_docs[].{"system_name": api_doc.system_name, "id": api_doc.id}'') }}'
- name: Get the production gateway endpoint from the proxy definition
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy.json?access_token={{ threescale_cicd_access_token|urlencode }}
validate_certs: no
method: GET
register: threescale_cicd_tmpresponse
when: "threescale_cicd_apicast_production_endpoint is not defined"
- name: Extract the production gateway endpoint from the proxy definition
set_fact:
threescale_cicd_apicast_production_endpoint: '{{ threescale_cicd_tmpresponse.json|json_query(''proxy.endpoint'') }}'
when: "threescale_cicd_apicast_production_endpoint is not defined"
- set_fact:
threescale_cicd_apicast_production_scheme: '{{ threescale_cicd_apicast_production_endpoint|regex_findall(''^(\w+)://'')|first }}'
threescale_cicd_apicast_production_hostname: '{{ threescale_cicd_apicast_production_endpoint|regex_findall(''^\w+://(.+)$'')|first }}'
- set_fact:
threescale_cicd_openapi_rewritten: '{{ threescale_cicd_openapi_file_content }}'
- name: Rewrite the OpenAPI file (schemes)
set_fact:
threescale_cicd_openapi_rewritten: '{{ threescale_cicd_openapi_rewritten|combine({ ''schemes'': [ threescale_cicd_apicast_production_scheme ] }) }}'
- name: Rewrite the OpenAPI file (host)
set_fact:
threescale_cicd_openapi_rewritten: '{{ threescale_cicd_openapi_rewritten|combine({ ''host'': threescale_cicd_apicast_production_hostname }) }}'
- name: Rewrite the Swagger file (swagger version as string)
set_fact:
threescale_cicd_openapi_rewritten: '{{ threescale_cicd_openapi_rewritten|combine({ ''swagger'': threescale_cicd_openapi_rewritten.swagger ~ "" }) }}'
- name: Add the RH-SSO endpoints to the OpenAPI securityDefinitions
set_fact:
threescale_cicd_api_security_definitions: '{{ threescale_cicd_api_security_definitions|combine({ threescale_cicd_api_security_scheme_name: (threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme_name]|combine({ ''authorizationUrl'': threescale_cicd_sso_realm_endpoint ~ ''/protocol/openid-connect/auth'', ''tokenUrl'': threescale_cicd_sso_realm_endpoint ~ ''/protocol/openid-connect/token'' })) }) }}'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- name: Add the RH-SSO default scope to the OpenAPI securityDefinitions
set_fact:
threescale_cicd_api_security_definitions: '{{ threescale_cicd_api_security_definitions|combine({ threescale_cicd_api_security_scheme_name: (threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme_name]|combine({ ''scopes'': threescale_cicd_default_oauth_scopes})) }) }}'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'' and ''scopes'' not in threescale_cicd_api_security_scheme'
- name: Rewrite the OpenAPI file (securityDefinitions)
set_fact:
threescale_cicd_openapi_rewritten: '{{ threescale_cicd_openapi_rewritten|combine({ ''securityDefinitions'': threescale_cicd_api_security_definitions }) }}'
- set_fact:
threescale_cicd_tmp_activedoc_payload:
name: '{{ threescale_cicd_api_name }}'
system_name: '{{ threescale_cicd_api_system_name }}'
body: '{{ threescale_cicd_openapi_rewritten|to_nice_json }}'
description: '{{ threescale_cicd_api_description }}'
published: 'true'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_tmp_activedoc_payload }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- set_fact:
threescale_cicd_api_activedocs_id: '{{ (threescale_cicd_existing_activedocs_details|selectattr(''system_name'', ''equalto'', threescale_cicd_api_system_name)|first).id }}'
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_activedocs'
- name: Update the ActiveDocs
uri:
url: 'https://{{ inventory_hostname }}/admin/api/active_docs/{{ threescale_cicd_api_activedocs_id }}.json'
validate_certs: no
method: PUT
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_activedocs'
- name: Create the ActiveDocs
uri:
url: https://{{ inventory_hostname }}/admin/api/active_docs.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_activedocs'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'
- set_fact:
threescale_cicd_api_activedocs_id: '{{ threescale_cicd_tmpresponse.json.api_doc.id }}'
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_activedocs'
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_existing_activedocs|union([ threescale_cicd_tmpresponse.json.api_doc.system_name ]) }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_existing_activedocs_details|union([ { ''id'': threescale_cicd_tmpresponse.json.api_doc.id, ''system_name'': threescale_cicd_tmpresponse.json.api_doc.system_name } ]) }}'
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_activedocs'

38
tasks/create_application_plans.yml

@ -1,38 +0,0 @@
---
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_tmp_plan }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- name: Update the application plan
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans/{{ (threescale_cicd_existing_application_plans_details|selectattr("system_name", "equalto", threescale_cicd_tmp_plan.system_name)|first).id }}.json'
validate_certs: no
method: PUT
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 200
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_tmp_plan.system_name in threescale_cicd_existing_application_plans'
- name: Create the application plan
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 201
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_tmp_plan.system_name not in threescale_cicd_existing_application_plans'
- set_fact:
threescale_cicd_existing_application_plans: '{{ threescale_cicd_existing_application_plans|union([ threescale_cicd_tmp_plan.system_name ]) }}'
threescale_cicd_existing_application_plans_details: '{{ threescale_cicd_existing_application_plans_details|union([{ "system_name": threescale_cicd_tmp_plan.system_name, "id": threescale_cicd_tmpresponse.json.application_plan.id }]) }}'
when: 'threescale_cicd_tmp_plan.system_name not in threescale_cicd_existing_application_plans'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

89
tasks/create_default_application.yml

@ -1,89 +0,0 @@
---
- name: Get the default (first) account
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts.json?access_token={{ threescale_cicd_access_token|urlencode }}&state=approved&page=1&per_page=1
validate_certs: no
register: threescale_cicd_tmp_allaccounts
when: 'threescale_cicd_default_account_id is not defined'
- set_fact:
threescale_cicd_default_account_id: '{{ threescale_cicd_tmp_allaccounts.json.accounts[0].account.id }}'
when: 'threescale_cicd_default_account_id is not defined'
- name: Pick the first given application plan if no default application plan is given
set_fact:
threescale_cicd_default_application_plan: '{{ (threescale_cicd_application_plans|first).system_name }}'
when: 'threescale_cicd_default_application_plan is not defined and threescale_cicd_application_plans is defined and threescale_cicd_application_plans|length > 0'
- name: Find the application plan id
set_fact:
threescale_cicd_default_application_plan_id: '{{ (threescale_cicd_existing_application_plans_details|selectattr("system_name", "equalto", threescale_cicd_default_application_plan)|first).id }}'
when: 'threescale_cicd_default_application_plan is defined'
- name: Compute the appid for the default application
set_fact:
# The default appid is a SHA1 hash of the application name, api name and salted with the 3scale access token so that it cannot be guessed
threescale_cicd_default_application_appid: '{{ (threescale_cicd_default_application_name ~ threescale_cicd_api_system_name ~ threescale_cicd_access_token)|hash(''sha1'') }}'
when: 'threescale_cicd_default_application_appid is not defined'
- set_fact:
threescale_cicd_tmp_search_criteria: 'app_id'
threescale_cicd_tmp_app_id_field: 'application_id'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- set_fact:
threescale_cicd_tmp_search_criteria: 'user_key'
threescale_cicd_tmp_app_id_field: 'user_key'
when: 'threescale_cicd_api_security_scheme.type == ''apiKey'''
- name: Check if the default application exists
uri:
url: 'https://{{ inventory_hostname }}/admin/api/applications/find.json?access_token={{ threescale_cicd_access_token|urlencode }}&{{ threescale_cicd_tmp_search_criteria }}={{ threescale_cicd_default_application_appid|urlencode }}'
validate_certs: no
method: GET
status_code: 200,404
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_default_application_id is not defined and threescale_cicd_default_application_appid is defined'
- set_fact:
threescale_cicd_default_application_id: '{{ threescale_cicd_tmpresponse.json.application.id }}'
when: 'threescale_cicd_default_application_id is not defined and threescale_cicd_default_application_appid is defined and threescale_cicd_tmpresponse.status == 200'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ (threescale_cicd_access_token|urlencode) ~ "&plan_id=" ~ threescale_cicd_default_application_plan_id ~ "&name=" ~ (threescale_cicd_default_application_name|urlencode) ~ "&description=" ~ (threescale_cicd_default_application_description|urlencode) ~ "&" ~ threescale_cicd_tmp_app_id_field ~ "=" ~ (threescale_cicd_default_application_appid|urlencode) }}'
- name: Create the application
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts/{{ threescale_cicd_default_account_id }}/applications.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 201
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_default_application_id is not defined'
- set_fact:
threescale_cicd_default_application_details: '{{ threescale_cicd_tmpresponse.json.application }}'
when: 'threescale_cicd_default_application_id is not defined'
- name: Update the application
uri:
url: https://{{ inventory_hostname }}/admin/api/accounts/{{ threescale_cicd_default_account_id }}/applications/{{ threescale_cicd_default_application_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 200
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_default_application_id is defined'
- set_fact:
threescale_cicd_default_application_details: '{{ threescale_cicd_tmpresponse.json.application }}'
when: 'threescale_cicd_default_application_id is defined'
- include_tasks: patch_default_application_for_oauth.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

28
tasks/create_mapping_rule.yml

@ -1,28 +0,0 @@
---
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_tmp_wanted_mapping_rules[threescale_cicd_tmp_mapping_rule_to_create] }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- set_fact:
# Add the metric_id to the payload
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ "metric_id=" ~ ((threescale_cicd_existing_metrics_details|selectattr("system_name", "equalto", threescale_cicd_tmp_mapping_rule_to_create)|first).id|urlencode) }}'
- name: Create the mapping rule
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

58
tasks/create_service.yml

@ -1,58 +0,0 @@
---
- name: Retrieve existing Services from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmp_allservices
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_tmp_allservices.json|json_query(''services[*].service.system_name'') }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_tmp_allservices.json|json_query(''services[].{"system_name": service.system_name, "id": service.id}'') }}'
- set_fact:
threescale_cicd_tmp_body_create_svc: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_create_svc: '{{ threescale_cicd_tmp_body_create_svc ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_api_service_definition }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- set_fact:
threescale_cicd_api_service_id: '{{ (threescale_cicd_existing_services_details|selectattr(''system_name'', ''equalto'', threescale_cicd_api_system_name)|first)[''id''] }}'
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_services'
- name: Update the service
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_tmp_body_create_svc }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_services'
- name: Create the service
uri:
url: https://{{ inventory_hostname }}/admin/api/services.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_create_svc }}'
status_code: 201
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_services'
- set_fact:
threescale_cicd_api_service_id: '{{ threescale_cicd_tmpresponse.json.service.id }}'
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_services'
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_existing_services|union([ threescale_cicd_tmpresponse.json.service.system_name ]) }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_existing_services_details|union([ { ''id'': threescale_cicd_tmpresponse.json.service.id, ''system_name'': threescale_cicd_tmpresponse.json.service.system_name } ]) }}'
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_services'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

25
tasks/delete_unused_metrics.yml

@ -1,25 +0,0 @@
---
- set_fact:
threescale_cicd_tmp_metrics_to_delete: []
- set_fact:
threescale_cicd_tmp_metrics_to_delete: '{{ threescale_cicd_tmp_metrics_to_delete|union([threescale_cicd_tmp_metric.id]) }}'
with_items: '{{ threescale_cicd_existing_metrics_details }}'
loop_control:
loop_var: threescale_cicd_tmp_metric
when: 'threescale_cicd_tmp_metric.system_name != "hits" and threescale_cicd_tmp_metric.system_name not in threescale_cicd_api_operations'
- name: Delete the method
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods/{{ threescale_cicd_tmp_metric }}.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
method: DELETE
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
with_items: '{{ threescale_cicd_tmp_metrics_to_delete }}'
loop_control:
loop_var: threescale_cicd_tmp_metric
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

142
tasks/main.yml

@ -1,143 +1,53 @@
---
- import_tasks: check_requirements.yml
# Make sure we have everything we need to run this playbook
- import_tasks: steps/requirements.yml
- name: Ensure pre-requisites are met
assert:
that:
- "threescale_cicd_access_token is defined"
- "threescale_cicd_openapi_file is defined"
msg: |-
This module requires at least two variables:
- 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=...)
- name: Set the threescale_cicd_sso_issuer_endpoint variable from the inventory
set_fact:
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 }}'
when: 'threescale_cicd_sso_issuer_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0'
- name: Set the threescale_cicd_sso_realm_endpoint variable from the threescale_cicd_sso_issuer_endpoint
set_fact:
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'')) }}'
when: 'threescale_cicd_sso_realm_endpoint is not defined and threescale_cicd_sso_issuer_endpoint is defined'
- name: Set the threescale_cicd_sso_admin_endpoint variable from the threescale_cicd_sso_realm_endpoint
set_fact:
threescale_cicd_sso_admin_endpoint: '{{ threescale_cicd_sso_realm_endpoint|replace(''/auth/realms/'', ''/auth/admin/realms/'') }}'
when: 'threescale_cicd_sso_admin_endpoint is not defined and threescale_cicd_sso_realm_endpoint is defined'
- name: Set the threescale_cicd_apicast_sandbox_endpoint variable from the inventory
set_fact:
threescale_cicd_apicast_sandbox_endpoint: '{{ (hostvars[groups[''apicast-sandbox''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''apicast-sandbox''][0] }}'
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'
# Compute missing variables from the inventory
- import_tasks: steps/variables_from_inventory.yml
# Load the API definition from the provided OpenAPI file
- import_tasks: read_openapi_file.yml
- 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:
msg: "Will work on service with system_name = {{ threescale_cicd_api_system_name }}"
- set_fact:
threescale_cicd_api_deployment_type: 'self_managed'
when: 'threescale_cicd_api_deployment_type is not defined and (threescale_cicd_apicast_sandbox_endpoint is defined or threescale_cicd_apicast_production_endpoint is defined)'
- set_fact:
threescale_cicd_api_deployment_type: 'hosted'
when: 'threescale_cicd_api_deployment_type is not defined'
- import_tasks: steps/read_openapi.yml
- set_fact:
threescale_cicd_api_service_definition:
name: '{{ threescale_cicd_api_name }}'
deployment_option: '{{ threescale_cicd_api_deployment_type }}'
system_name: '{{ threescale_cicd_api_system_name }}'
backend_version: '{{ threescale_cicd_api_backend_version }}'
# Discover the current state of the platform
- import_tasks: steps/discover.yml
# Create the service definition
- import_tasks: create_service.yml
# Create or update the service definition
- import_tasks: steps/service.yml
- set_fact:
threescale_cicd_api_credentials_location: '{{ ''headers'' if threescale_cicd_api_security_scheme.in == ''header'' else threescale_cicd_api_security_scheme.in }}'
when: 'threescale_cicd_api_security_scheme.type == ''apiKey'''
# Create or update the methods
- import_tasks: steps/methods.yml
- set_fact:
threescale_cicd_api_credentials_location: 'headers'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- set_fact:
threescale_cicd_api_proxy_definition:
credentials_location: '{{ threescale_cicd_api_credentials_location }}'
api_backend: '{{ threescale_cicd_private_base_url }}'
- set_fact:
threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''auth_user_key'': threescale_cicd_api_security_scheme.name }) }}'
when: 'threescale_cicd_api_security_scheme.type == ''apiKey'''
- set_fact:
threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''oidc_issuer_endpoint'': threescale_cicd_sso_issuer_endpoint }) }}'
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- set_fact:
threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''sandbox_endpoint'': threescale_cicd_apicast_sandbox_endpoint }) }}'
when: 'threescale_cicd_apicast_sandbox_endpoint is defined'
- set_fact:
threescale_cicd_api_proxy_definition: '{{ threescale_cicd_api_proxy_definition|combine({ ''endpoint'': threescale_cicd_apicast_production_endpoint }) }}'
when: 'threescale_cicd_apicast_production_endpoint is defined'
# Update the metrics
- import_tasks: update_metrics.yml
# Update the mapping rules
- import_tasks: update_mapping_rules.yml
# Create, update or delete the mapping rules
- import_tasks: steps/mapping_rules.yml
# Update the proxy
- import_tasks: update_proxy.yml
- import_tasks: steps/proxy.yml
- name: Get the list of existing application plans
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans.json?access_token={{ threescale_cicd_access_token|urlencode }}
validate_certs: no
register: threescale_cicd_tmpresponse
# Create or update application plans
- import_tasks: steps/application_plans.yml
- set_fact:
threescale_cicd_existing_application_plans: '{{ threescale_cicd_tmpresponse.json|json_query(''plans[*].application_plan.system_name'') }}'
threescale_cicd_existing_application_plans_details: '{{ threescale_cicd_tmpresponse.json|json_query(''plans[].{"system_name": application_plan.system_name, "id": application_plan.id}'') }}'
# Create application plans if needed
- include_tasks: create_application_plans.yml
with_items: '{{ threescale_cicd_application_plans|default([]) }}'
loop_control:
loop_var: threescale_cicd_tmp_plan
# Create or update the default application if smoke tests are needed
- include_tasks: steps/default_application.yml
when: 'threescale_cicd_openapi_smoketest_path is defined and threescale_cicd_application_plans is defined'
# Run smoke tests on the staging gateway
- include_tasks: smoke_tests.yml
- include_tasks: steps/smoke_test.yml
vars:
threescale_cicd_env: staging
threescale_cicd_smoke_test_env: staging
when: 'threescale_cicd_openapi_smoketest_path is defined and threescale_cicd_application_plans is defined'
# Promote to production
- import_tasks: promote.yml
- import_tasks: steps/promote.yml
# Run smoke tests on the production gateway
- include_tasks: smoke_tests.yml
- include_tasks: steps/smoke_test.yml
vars:
threescale_cicd_env: production
threescale_cicd_smoke_test_env: production
when: 'threescale_cicd_openapi_smoketest_path is defined and threescale_cicd_application_plans is defined'
# Delete the metrics that are not needed anymore
- import_tasks: delete_unused_metrics.yml
- import_tasks: steps/cleanup_metrics.yml
# Publish the OpenAPI Specifications file on the 3scale Admin Portal
- import_tasks: create_activedocs.yml
- import_tasks: steps/activedoc.yml

65
tasks/patch_default_application_for_oauth.yml

@ -1,65 +0,0 @@
---
- name: Prepare the OAuth Request to RH-SSO (static params)
set_fact:
threescale_cicd_tmp_body: ""
- name: Prepare the OAuth Request to RH-SSO (urlencode dynamic params)
set_fact:
threescale_cicd_tmp_body: '{{ threescale_cicd_tmp_body ~ "&" ~ threescale_cicd_tmp_param.key ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict:
client_id: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''username'') }}'
client_secret: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''password'') }}'
scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}'
grant_type: client_credentials
loop_control:
loop_var: threescale_cicd_tmp_param
- name: Authenticate to RH-SSO using the 3scale service account
uri:
url: '{{ threescale_cicd_sso_realm_endpoint }}/protocol/openid-connect/token'
body: '{{ threescale_cicd_tmp_body }}'
method: POST
validate_certs: no
return_content: yes
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
# temporary fix for https://github.com/ansible/ansible/issues/28078
until: 'threescale_cicd_tmpresponse|success'
- name: Extract the access_token
set_fact:
threescale_cicd_openapi_tmp_access_token: '{{ threescale_cicd_tmpresponse.json |json_query("access_token") }}'
- name: Wait for the new client to appear in RH-SSO
uri:
url: '{{ threescale_cicd_sso_admin_endpoint }}/clients?clientId={{ threescale_cicd_default_application_appid|urlencode }}'
method: GET
validate_certs: no
return_content: yes
headers:
Authorization: 'Bearer {{ threescale_cicd_openapi_tmp_access_token }}'
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
until: 'threescale_cicd_tmpresponse|success and threescale_cicd_tmpresponse.json|length > 0'
- set_fact:
threescale_cicd_default_application_sso_id: '{{ threescale_cicd_tmpresponse.json[0].id }}'
threescale_cicd_tmp_body: '{{ threescale_cicd_tmpresponse.json[0]|combine({ ''serviceAccountsEnabled'': true, ''standardFlowEnabled'': false, ''implicitFlowEnabled'': false, ''directAccessGrantsEnabled'': true }) }}'
- name: Patch the client in RH-SSO to support the "client_credentials" and "password" grant_type.
uri:
url: '{{ threescale_cicd_sso_admin_endpoint }}/clients/{{ threescale_cicd_default_application_sso_id|urlencode }}'
method: PUT
validate_certs: no
body: '{{ threescale_cicd_tmp_body|to_json }}'
status_code: '200,204'
headers:
Authorization: 'Bearer {{ threescale_cicd_openapi_tmp_access_token }}'
Content-Type: 'application/json'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

42
tasks/promote.yml

@ -1,42 +0,0 @@
---
- name: Get the version of the staging proxy definition
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_staging_environment_name }}/latest.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_tmp_staging_proxy_version: '{{ threescale_cicd_tmpresponse.json.proxy_config.version }}'
- name: Get the version of the production proxy definition
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_production_environment_name }}/latest.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
status_code: 200,404
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_tmp_production_proxy_version: '{{ threescale_cicd_tmpresponse.json.proxy_config.version }}'
when: 'threescale_cicd_tmpresponse.status == 200'
- set_fact:
threescale_cicd_tmp_production_proxy_version: 'NONE'
when: 'threescale_cicd_tmpresponse.status == 404'
- set_fact:
threescale_cicd_tmp_body_create_svc: 'access_token={{ threescale_cicd_access_token|urlencode }}&to={{ threescale_cicd_production_environment_name|urlencode }}'
- name: Promote to production
uri:
url: 'https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/configs/{{ threescale_cicd_staging_environment_name }}/{{ threescale_cicd_tmp_staging_proxy_version }}/promote.json'
body: '{{ threescale_cicd_tmp_body_create_svc }}'
status_code: 201
validate_certs: no
method: POST
register: threescale_cicd_tmpresponse
when: 'threescale_cicd_tmp_staging_proxy_version != threescale_cicd_tmp_production_proxy_version'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

59
tasks/smoke_tests.yml

@ -1,59 +0,0 @@
---
- import_tasks: create_default_application.yml
- set_fact:
threescale_cicd_tmp_gateway_endpoint: ""
- name: Try to get the staging gateway url from extra var / inventory
set_fact:
threescale_cicd_tmp_gateway_endpoint: '{{ threescale_cicd_apicast_sandbox_endpoint }}'
when: "threescale_cicd_apicast_sandbox_endpoint is defined and threescale_cicd_env == 'staging'"
- name: Try to get the production gateway url from extra var / inventory
set_fact:
threescale_cicd_tmp_gateway_endpoint: '{{ threescale_cicd_apicast_production_endpoint }}'
when: "threescale_cicd_apicast_production_endpoint is defined and threescale_cicd_env == 'production'"
- name: Get the gateway endpoint from the proxy definition
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy.json?access_token={{ threescale_cicd_access_token|urlencode }}
validate_certs: no
method: GET
register: threescale_cicd_tmpresponse
when: "threescale_cicd_tmp_gateway_endpoint|length == 0"
- name: Extract the staging gateway endpoint from the proxy definition
set_fact:
threescale_cicd_tmp_gateway_endpoint: '{{ threescale_cicd_tmpresponse.json|json_query(''proxy.sandbox_endpoint'') }}'
when: "threescale_cicd_tmp_gateway_endpoint|length == 0 and threescale_cicd_env == 'staging'"
- name: Extract the production gateway endpoint from the proxy definition
set_fact:
threescale_cicd_tmp_gateway_endpoint: '{{ threescale_cicd_tmpresponse.json|json_query(''proxy.endpoint'') }}'
when: "threescale_cicd_tmp_gateway_endpoint|length == 0 and threescale_cicd_env == 'production'"
- set_fact:
threescale_cicd_openapi_smoketest_querystring: ""
threescale_cicd_openapi_smoketest_headers: {}
- include_tasks: smoke_tests_apikey.yml
when: 'threescale_cicd_api_security_scheme.type == ''apiKey'''
- include_tasks: smoke_tests_oauth.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- debug:
msg: "Starting a smoke test on '{{ threescale_cicd_tmp_gateway_endpoint }}{{ threescale_cicd_openapi_smoketest_path }}'..."
- name: Running smoke tests !
uri:
url: '{{ threescale_cicd_tmp_gateway_endpoint }}{{ threescale_cicd_openapi_smoketest_path }}{{ threescale_cicd_openapi_smoketest_querystring }}'
headers: '{{ threescale_cicd_openapi_smoketest_headers }}'
validate_certs: no
method: GET
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
# temporary fix for https://github.com/ansible/ansible/issues/28078
until: 'threescale_cicd_tmpresponse|success'

9
tasks/smoke_tests_apikey.yml

@ -1,9 +0,0 @@
---
- set_fact:
threescale_cicd_openapi_smoketest_querystring: "?{{ threescale_cicd_api_security_scheme.name|urlencode }}={{ threescale_cicd_default_application_details.user_key }}"
when: 'threescale_cicd_api_credentials_location == "query"'
- set_fact:
threescale_cicd_openapi_smoketest_headers: "{{ threescale_cicd_openapi_smoketest_headers|combine({ threescale_cicd_api_security_scheme.name|urlencode: threescale_cicd_default_application_details.user_key}) }}"
when: 'threescale_cicd_api_credentials_location == "headers"'

36
tasks/smoke_tests_oauth.yml

@ -1,36 +0,0 @@
---
- name: Prepare the OAuth Request to RH-SSO (static params)
set_fact:
threescale_cicd_tmp_body: ""
- name: Prepare the OAuth Request to RH-SSO (urlencode dynamic params)
set_fact:
threescale_cicd_tmp_body: '{{ threescale_cicd_tmp_body ~ "&" ~ threescale_cicd_tmp_param.key ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict:
client_id: '{{ threescale_cicd_default_application_details.client_id }}'
client_secret: '{{ threescale_cicd_default_application_details.client_secret }}'
scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}'
grant_type: client_credentials
loop_control:
loop_var: threescale_cicd_tmp_param
- name: Authenticate to RH-SSO using the default application credentials
uri:
url: '{{ threescale_cicd_sso_realm_endpoint }}/protocol/openid-connect/token'
body: '{{ threescale_cicd_tmp_body }}'
method: POST
validate_certs: no
return_content: yes
register: threescale_cicd_tmpresponse
retries: '{{ threescale_cicd_retries }}'
delay: '{{ threescale_cicd_delay }}'
# temporary fix for https://github.com/ansible/ansible/issues/28078
until: 'threescale_cicd_tmpresponse|success'
- name: Extract the access_token
set_fact:
threescale_cicd_openapi_smoketest_access_token: '{{ threescale_cicd_tmpresponse.json |json_query("access_token") }}'
- set_fact:
threescale_cicd_openapi_smoketest_headers: "{{ threescale_cicd_openapi_smoketest_headers|combine({ 'Authorization': 'Bearer ' ~ threescale_cicd_openapi_smoketest_access_token }) }}"

9
tasks/steps/activedoc.yml

@ -0,0 +1,9 @@
---
- debug:
msg: '{{ threescale_cicd_openapi_rewritten }}'
- include_tasks: api-calls/update_activedoc.yml
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_activedocs'
- include_tasks: api-calls/create_activedoc.yml
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_activedocs'

8
tasks/steps/application_plan.yml

@ -0,0 +1,8 @@
---
- include_tasks: api-calls/update_application_plan.yml
when: 'threescale_cicd_application_plan.system_name in threescale_cicd_existing_application_plans'
- include_tasks: api-calls/create_application_plan.yml
when: 'threescale_cicd_application_plan.system_name not in threescale_cicd_existing_application_plans'

6
tasks/steps/application_plans.yml

@ -0,0 +1,6 @@
---
- include_tasks: steps/application_plan.yml
with_items: '{{ threescale_cicd_application_plans|default([]) }}'
loop_control:
loop_var: threescale_cicd_application_plan

6
tasks/steps/cleanup_metrics.yml

@ -0,0 +1,6 @@
---
- include_tasks: "api-calls/delete_metric.yml"
with_items: '{{ threescale_cicd_metrics_to_delete }}'
loop_control:
loop_var: threescale_cicd_metric

33
tasks/steps/default_application.yml

@ -0,0 +1,33 @@
---
- import_tasks: "api-calls/find_first_account.yml"
when: 'threescale_cicd_default_account_id is not defined'
- import_tasks: "api-calls/find_application.yml"
when: 'threescale_cicd_default_application_id is not defined'
- import_tasks: "api-calls/update_application.yml"
when: 'threescale_cicd_default_application_id is defined'
- import_tasks: "api-calls/create_application.yml"
when: 'threescale_cicd_default_application_id is not defined'
##
## When using OAuth / OIDC authentication, we need to patch the Keycloak client
## to support the client_credentials grant.
##
- include_tasks: api-calls/keycloak/authenticate.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
vars:
oauth_payload:
client_id: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''username'') }}'
client_secret: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''password'') }}'
scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}'
grant_type: 'client_credentials'
- include_tasks: api-calls/keycloak/wait_for_client.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
- include_tasks: api-calls/keycloak/patch_client.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''

47
tasks/steps/discover.yml

@ -0,0 +1,47 @@
---
- name: Retrieve existing Services from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmpresponse
when: threescale_cicd_existing_services is not defined
- set_fact:
threescale_cicd_existing_services: '{{ threescale_cicd_tmpresponse.json|json_query(''services[*].service.system_name'') }}'
threescale_cicd_existing_services_details: '{{ threescale_cicd_tmpresponse.json|json_query(''services[].{"system_name": service.system_name, "id": service.id}'') }}'
cacheable: true
when: threescale_cicd_existing_services is not defined
- debug:
msg: "Found {{ threescale_cicd_existing_services|length }} services"
verbosity: 1
- name: Get the list of existing application plans
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/application_plans.json?access_token={{ threescale_cicd_access_token|urlencode }}
validate_certs: no
register: threescale_cicd_tmpresponse
when: threescale_cicd_api_system_name in threescale_cicd_existing_services
- set_fact:
threescale_cicd_existing_application_plans: '{{ threescale_cicd_tmpresponse.json|json_query(''plans[*].application_plan.system_name'') if threescale_cicd_api_system_name in threescale_cicd_existing_services else [] }}'
threescale_cicd_existing_application_plans_details: '{{ threescale_cicd_tmpresponse.json|json_query(''plans[].{"system_name": application_plan.system_name, "id": application_plan.id}'') if threescale_cicd_api_system_name in threescale_cicd_existing_services else [] }}'
- debug:
msg: "Found {{ threescale_cicd_existing_application_plans|length }} application plans"
verbosity: 1
- name: Retrieve existing ActiveDocs from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/active_docs.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmp_allactivedocs
- set_fact:
threescale_cicd_existing_activedocs: '{{ threescale_cicd_tmp_allactivedocs.json|json_query(''api_docs[*].api_doc.system_name'') }}'
threescale_cicd_existing_activedocs_details: '{{ threescale_cicd_tmp_allactivedocs.json|json_query(''api_docs[].{"system_name": api_doc.system_name, "id": api_doc.id}'') }}'
- debug:
msg: "Found {{ threescale_cicd_existing_activedocs|length }} active docs"
verbosity: 1

25
tasks/steps/mapping_rules.yml

@ -0,0 +1,25 @@
---
- name: Retrieve existing mapping rules from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_existing_mapping_rules_details: '{{ threescale_cicd_tmpresponse.json|json_query(''mapping_rules[].{"metric_id": mapping_rule.metric_id, "id": mapping_rule.id}'') }}'
- include_tasks: "api-calls/create_mapping_rule.yml"
with_items: '{{ threescale_cicd_mapping_rules_to_create }}'
loop_control:
loop_var: threescale_cicd_mapping_rule
- include_tasks: "api-calls/update_mapping_rule.yml"
with_items: '{{ threescale_cicd_mapping_rules_to_update }}'
loop_control:
loop_var: threescale_cicd_mapping_rule
- include_tasks: "api-calls/delete_mapping_rule.yml"
with_items: '{{ threescale_cicd_mapping_rules_to_delete }}'
loop_control:
loop_var: threescale_cicd_mapping_rule

7
tasks/steps/method.yml

@ -0,0 +1,7 @@
---
- include_tasks: api-calls/update_method.yml
when: 'threescale_cicd_api_operation.key in threescale_cicd_existing_metrics'
- include_tasks: api-calls/create_method.yml
when: 'threescale_cicd_api_operation.key not in threescale_cicd_existing_metrics'

16
tasks/steps/methods.yml

@ -0,0 +1,16 @@
---
- name: Retrieve existing metrics from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmpresponse
- set_fact:
threescale_cicd_existing_metrics: '{{ threescale_cicd_tmpresponse.json|json_query(''metrics[*].metric.system_name'') }}'
threescale_cicd_existing_metrics_details: '{{ threescale_cicd_tmpresponse.json|json_query(''metrics[].{"system_name": metric.system_name, "id": metric.id}'') }}'
- include_tasks: "steps/method.yml"
with_dict: '{{ threescale_cicd_api_operations }}'
loop_control:
loop_var: threescale_cicd_api_operation

6
tasks/steps/promote.yml

@ -0,0 +1,6 @@
---
- import_tasks: "api-calls/get_proxy_version.yml"
- include_tasks: "api-calls/promote_proxy.yml"
when: 'threescale_cicd_staging_proxy_version != threescale_cicd_production_proxy_version'

3
tasks/steps/proxy.yml

@ -0,0 +1,3 @@
---
- import_tasks: api-calls/update_proxy.yml

9
tasks/read_openapi_file.yml → tasks/steps/read_openapi.yml

@ -186,3 +186,12 @@
- 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:
msg: "Will work on service with system_name = {{ threescale_cicd_api_system_name }}"

57
tasks/steps/requirements.yml

@ -0,0 +1,57 @@
---
- name: Ensure pre-requisites are met
assert:
that:
- "threescale_cicd_access_token is defined"
- "threescale_cicd_openapi_file is defined"
msg: |-
This module requires at least two variables:
- 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=...)
- name: Verify that Ansible version is >= 2.4
assert:
that: "ansible_version.full is version_compare('2.4', '>=')"
msg: This module requires at least Ansible 2.4
- name: Check if jmespath is installed locally
debug: msg={{dummy|json_query('@')}}
register: check_jmespath
ignore_errors: yes
vars:
dummy: Hello World
- name: Check if jinja 2.8 is installed locally
debug: msg={{(dummy|selectattr("id", "equalto", "hello")|first)['value']}}
vars:
dummy:
- id: hello
value: Hello World
register: check_jinja28
ignore_errors: yes
- name: Check if the "do" jinja extension is enabled
debug: msg={% do {}.update({}) %}{{ success }}
vars:
success: 'The do extension is enabled'
register: check_jinja_do_ext
ignore_errors: yes
- assert:
that:
- 'check_jmespath is success'
msg: "The JMESPath library is required by this role. Please install the JMESPath library with 'pip install jmespath'."
- assert:
that:
- 'check_jinja28 is success'
msg: "At least Jinja v2.8 is required by this role. Please update Jinja with 'pip install -U Jinja2'."
- assert:
that:
- 'check_jinja_do_ext is success'
msg: |-
You need to enable the 'do' extension of Jinja in your ansible.cfg:
[default]
jinja2_extensions = jinja2.ext.do

7
tasks/steps/service.yml

@ -0,0 +1,7 @@
---
- include_tasks: api-calls/update_service.yml
when: 'threescale_cicd_api_system_name in threescale_cicd_existing_services'
- include_tasks: api-calls/create_service.yml
when: 'threescale_cicd_api_system_name not in threescale_cicd_existing_services'

14
tasks/steps/smoke_test.yml

@ -0,0 +1,14 @@
---
# Retrieve a valid access token if the API is secured with OAuth/OIDC
- include_tasks: api-calls/keycloak/authenticate.yml
when: 'threescale_cicd_api_security_scheme.type == ''oauth2'''
vars:
oauth_payload:
client_id: '{{ threescale_cicd_default_application_details.client_id }}'
client_secret: '{{ threescale_cicd_default_application_details.client_secret }}'
scope: '{{ threescale_cicd_openapi_smoketest_default_scope }}'
grant_type: 'client_credentials'
# Do the smoke test
- import_tasks: api-calls/smoke_test.yml

26
tasks/steps/variables_from_inventory.yml

@ -0,0 +1,26 @@
---
- name: Set the threescale_cicd_sso_issuer_endpoint variable from the inventory
set_fact:
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 }}'
when: 'threescale_cicd_sso_issuer_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0'
- name: Set the threescale_cicd_sso_realm_endpoint variable from the threescale_cicd_sso_issuer_endpoint
set_fact:
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'')) }}'
when: 'threescale_cicd_sso_realm_endpoint is not defined and threescale_cicd_sso_issuer_endpoint is defined'
- name: Set the threescale_cicd_sso_admin_endpoint variable from the threescale_cicd_sso_realm_endpoint
set_fact:
threescale_cicd_sso_admin_endpoint: '{{ threescale_cicd_sso_realm_endpoint|replace(''/auth/realms/'', ''/auth/admin/realms/'') }}'
when: 'threescale_cicd_sso_admin_endpoint is not defined and threescale_cicd_sso_realm_endpoint is defined'
- name: Set the threescale_cicd_apicast_sandbox_endpoint variable from the inventory
set_fact:
threescale_cicd_apicast_sandbox_endpoint: '{{ (hostvars[groups[''apicast-sandbox''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''apicast-sandbox''][0] }}'
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'

30
tasks/update_mapping_rule.yml

@ -1,30 +0,0 @@
---
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_tmp_wanted_mapping_rules[threescale_cicd_tmp_mapping_rule_to_update] }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- set_fact:
# Add the metric_id to the payload
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ "metric_id=" ~ ((threescale_cicd_existing_metrics_details|selectattr("system_name", "equalto", threescale_cicd_tmp_mapping_rule_to_update)|first).id|urlencode) }}'
# The ID of the mapping rule to update
threescale_cicd_tmp_mapping_rule_id: '{{ threescale_cicd_tmp_existing_mapping_rules[threescale_cicd_tmp_mapping_rule_to_update] }}'
- name: Update the mapping rule
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules/{{ threescale_cicd_tmp_mapping_rule_id }}.json
validate_certs: no
method: PUT
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 200
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

59
tasks/update_mapping_rules.yml

@ -1,59 +0,0 @@
---
- name: Retrieve existing mapping rules from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmp_allmappingrules
- set_fact:
threescale_cicd_existing_mappingrules_details: '{{ threescale_cicd_tmp_allmappingrules.json|json_query(''mapping_rules[].{"metric_id": mapping_rule.metric_id, "id": mapping_rule.id}'') }}'
threescale_cicd_tmp_wanted_mapping_rules: {}
threescale_cicd_tmp_existing_mapping_rules: {}
- name: Build a list of our expected/wanted mapping rules
set_fact:
threescale_cicd_tmp_wanted_mapping_rules: '{{ threescale_cicd_tmp_wanted_mapping_rules|combine({ threescale_cicd_tmp_operation.key: { "http_method": threescale_cicd_tmp_operation.value.verb.upper(), "pattern": threescale_cicd_api_basepath ~ threescale_cicd_tmp_operation.value.path ~ "$", "delta": 1 } }) }}'
with_dict: '{{ threescale_cicd_api_operations }}'
loop_control:
loop_var: threescale_cicd_tmp_operation
- name: Map metric id to system_name
set_fact:
threescale_cicd_tmp_existing_mapping_rules: '{{ threescale_cicd_tmp_existing_mapping_rules|combine({ (threescale_cicd_existing_metrics_details|selectattr("id", "equalto", threescale_cicd_tmp_metric.metric_id)|first).system_name: threescale_cicd_tmp_metric.id}) }}'
with_items: '{{ threescale_cicd_existing_mappingrules_details }}'
loop_control:
loop_var: threescale_cicd_tmp_metric
- set_fact:
# create the items that we want but don't have yet
threescale_cicd_tmp_mapping_rules_to_create: '{{ threescale_cicd_tmp_wanted_mapping_rules.keys()|difference(threescale_cicd_tmp_existing_mapping_rules.keys()) }}'
# delete the items that we don't want but we have
threescale_cicd_tmp_mapping_rules_to_delete: '{{ threescale_cicd_tmp_existing_mapping_rules.keys()|difference(threescale_cicd_tmp_wanted_mapping_rules.keys()) }}'
# update the items that we want and we have
threescale_cicd_tmp_mapping_rules_to_update: '{{ threescale_cicd_tmp_existing_mapping_rules.keys()|intersect(threescale_cicd_tmp_wanted_mapping_rules.keys()) }}'
- include_tasks: "create_mapping_rule.yml"
with_items: '{{ threescale_cicd_tmp_mapping_rules_to_create }}'
loop_control:
loop_var: threescale_cicd_tmp_mapping_rule_to_create
- include_tasks: "update_mapping_rule.yml"
with_items: '{{ threescale_cicd_tmp_mapping_rules_to_update }}'
loop_control:
loop_var: threescale_cicd_tmp_mapping_rule_to_update
- name: Delete the unused mapping rules
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/mapping_rules/{{ threescale_cicd_tmp_existing_mapping_rules[threescale_cicd_tmp_mapping_rule_to_delete] }}.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
method: DELETE
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
with_items: '{{ threescale_cicd_tmp_mapping_rules_to_delete }}'
loop_control:
loop_var: threescale_cicd_tmp_mapping_rule_to_delete
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

47
tasks/update_method.yml

@ -1,47 +0,0 @@
---
- set_fact:
threescale_cicd_api_method_definition:
system_name: '{{ threescale_cicd_tmp_operation.key }}'
friendly_name: '{{ threescale_cicd_tmp_operation.value.friendly_name|default(threescale_cicd_tmp_operation.key) }}'
description: '{{ threescale_cicd_tmp_operation.value.description|default('''') }}'
unit: 'hits'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_method: '{{ threescale_cicd_tmp_body_update_method ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_api_method_definition }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- name: Update the method
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods/{{ (threescale_cicd_existing_metrics_details|selectattr('system_name', 'equalto', threescale_cicd_tmp_operation.key)|first).id }}.json
validate_certs: no
method: PATCH
body: '{{ threescale_cicd_tmp_body_update_method }}'
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
when: 'threescale_cicd_tmp_operation.key in threescale_cicd_existing_metrics'
- name: Create the method
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics/{{ threescale_cicd_metric_id }}/methods.json
validate_certs: no
method: POST
body: '{{ threescale_cicd_tmp_body_update_method }}'
status_code: 201
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 201'
when: 'threescale_cicd_tmp_operation.key not in threescale_cicd_existing_metrics'
- set_fact:
threescale_cicd_existing_metrics: '{{ threescale_cicd_existing_metrics|union([ threescale_cicd_tmp_operation.key ]) }}'
threescale_cicd_existing_metrics_details: '{{ threescale_cicd_existing_metrics_details|union([ { "system_name": threescale_cicd_tmp_operation.key, "id": threescale_cicd_tmpresponse.json|json_query("method.id") } ]) }}'
when: 'threescale_cicd_tmp_operation.key not in threescale_cicd_existing_metrics'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

20
tasks/update_metrics.yml

@ -1,20 +0,0 @@
---
- name: Retrieve existing metrics from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/metrics.json?access_token={{ threescale_cicd_access_token|urlencode }}"
validate_certs: no
register: threescale_cicd_tmp_allmetrics
- set_fact:
threescale_cicd_existing_metrics: '{{ threescale_cicd_tmp_allmetrics.json|json_query(''metrics[*].metric.system_name'') }}'
threescale_cicd_existing_metrics_details: '{{ threescale_cicd_tmp_allmetrics.json|json_query(''metrics[].{"system_name": metric.system_name, "id": metric.id}'') }}'
- name: Find the "hits" metric id
set_fact:
threescale_cicd_metric_id: '{{ (threescale_cicd_existing_metrics_details|selectattr(''system_name'', ''equalto'', ''hits'')|first).id }}'
- include_tasks: "update_method.yml"
with_dict: '{{ threescale_cicd_api_operations }}'
loop_control:
loop_var: threescale_cicd_tmp_operation

23
tasks/update_proxy.yml

@ -1,23 +0,0 @@
---
- set_fact:
threescale_cicd_tmp_body_update_proxy: '{{ "access_token=" ~ threescale_cicd_access_token|urlencode }}'
- set_fact:
threescale_cicd_tmp_body_update_proxy: '{{ threescale_cicd_tmp_body_update_proxy ~ "&" ~ (threescale_cicd_tmp_param.key|urlencode) ~ "=" ~ (threescale_cicd_tmp_param.value|urlencode) }}'
with_dict: '{{ threescale_cicd_api_proxy_definition }}'
loop_control:
loop_var: threescale_cicd_tmp_param
- name: Update the proxy
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy.json
validate_certs: no
method: PATCH
body: '{{ threescale_cicd_tmp_body_update_proxy }}'
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

11
templates/api-calls/create_activedoc.j2

@ -0,0 +1,11 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'name=' ~ threescale_cicd_api_name|urlencode,
'description=' ~ threescale_cicd_api_description|urlencode,
'system_name=' ~ threescale_cicd_api_system_name|urlencode,
'body=' ~ threescale_cicd_openapi_rewritten|to_nice_json|urlencode,
'published=true',
]
%}
{{ payload|join("&") }}

15
templates/api-calls/create_application.j2

@ -0,0 +1,15 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'plan_id=' ~ threescale_cicd_default_application_plan_id|urlencode,
'name=' ~ threescale_cicd_default_application_name|urlencode,
'description=' ~ threescale_cicd_default_application_description|urlencode
]
%}
{% if threescale_cicd_api_security_scheme.type == 'oauth2' %}
{% do payload.append("application_id=" ~ threescale_cicd_default_application_appid|urlencode) %}
{% endif %}
{% if threescale_cicd_api_security_scheme.type == 'apiKey' %}
{% do payload.append("user_key=" ~ threescale_cicd_default_application_appid|urlencode) %}
{% endif %}
{{ payload|join("&") }}

9
templates/api-calls/create_application_plan.j2

@ -0,0 +1,9 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode
]
%}
{% for key, value in threescale_cicd_application_plan.items() %}
{% do payload.append(key ~ "=" ~ value|urlencode) %}
{% endfor %}
{{ payload|join("&") }}

10
templates/api-calls/create_mapping_rule.j2

@ -0,0 +1,10 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'metric_id=' ~ ((threescale_cicd_existing_metrics_details|selectattr("system_name", "equalto", threescale_cicd_mapping_rule)|first).id|urlencode)
]
%}
{% for key, value in threescale_cicd_wanted_mapping_rules[threescale_cicd_mapping_rule].items() %}
{% do payload.append(key ~ "=" ~ value|urlencode) %}
{% endfor %}
{{ payload|join("&") }}

10
templates/api-calls/create_method.j2

@ -0,0 +1,10 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'friendly_name=' ~ threescale_cicd_api_operation.value.friendly_name|default(threescale_cicd_api_operation.key)|urlencode,
'description=' ~ threescale_cicd_api_operation.value.description|default('')|urlencode,
'system_name=' ~ threescale_cicd_api_operation.key|urlencode,
'unit=hits'
]
%}
{{ payload|join("&") }}

10
templates/api-calls/create_service.j2

@ -0,0 +1,10 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'name=' ~ threescale_cicd_api_name|urlencode,
'deployment_option=' ~ threescale_cicd_api_deployment_type|urlencode,
'system_name=' ~ threescale_cicd_api_system_name|urlencode,
'backend_version=' ~ threescale_cicd_api_backend_version|urlencode
]
%}
{{ payload|join("&") }}

7
templates/api-calls/find_application.j2

@ -0,0 +1,7 @@
access_token={{ threescale_cicd_access_token|urlencode }}
{%- if threescale_cicd_api_security_scheme.type == 'oauth2' -%}
&app_id={{ threescale_cicd_default_application_appid|urlencode }}
{%- endif -%}
{%- if threescale_cicd_api_security_scheme.type == 'apiKey' -%}
&user_key={{ threescale_cicd_default_application_appid|urlencode }}
{%- endif -%}

5
templates/api-calls/keycloak/authenticate.j2

@ -0,0 +1,5 @@
{% set payload = [ ] %}
{% for key, value in oauth_payload.items() %}
{% do payload.append(key ~ "=" ~ value|urlencode) %}
{% endfor %}
{{ payload|join("&") }}

1
templates/api-calls/keycloak/patch_client.j2

@ -0,0 +1 @@
{{ threescale_cicd_default_application_sso_body|combine({ 'serviceAccountsEnabled': true, 'standardFlowEnabled': false, 'implicitFlowEnabled': false, 'directAccessGrantsEnabled': true }) }}

1
templates/api-calls/promote_proxy.j2

@ -0,0 +1 @@
access_token={{ threescale_cicd_access_token|urlencode }}&to={{ threescale_cicd_production_environment_name|urlencode }}

8
templates/api-calls/smoke-test/headers.j2

@ -0,0 +1,8 @@
{% set headers = {} %}
{% if threescale_cicd_api_security_scheme.type == "apiKey" and threescale_cicd_api_credentials_location == "headers" %}
{% do headers.update({ threescale_cicd_api_security_scheme.name|urlencode: threescale_cicd_default_application_details.user_key }) %}
{% endif %}
{% if threescale_cicd_api_security_scheme.type == "oauth2" and threescale_cicd_api_credentials_location == "headers" %}
{% do headers.update({ 'Authorization': 'Bearer ' ~ threescale_cicd_keycloak_access_token }) %}
{% endif %}
{{ headers }}

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

@ -0,0 +1,10 @@
{%- if threescale_cicd_smoke_test_env == "staging" -%}
{{ threescale_cicd_apicast_sandbox_endpoint }}
{%- endif -%}
{%- if threescale_cicd_smoke_test_env == "production" -%}
{{ threescale_cicd_apicast_production_endpoint }}
{%- endif -%}
{{ threescale_cicd_openapi_smoketest_path }}
{%- if threescale_cicd_api_security_scheme.type == "apiKey" and threescale_cicd_api_credentials_location == "query" -%}
?{{ threescale_cicd_api_security_scheme.name|urlencode }}={{ threescale_cicd_default_application_details.user_key }}
{%- endif -%}

1
templates/api-calls/update_activedoc.j2

@ -0,0 +1 @@
create_activedoc.j2

1
templates/api-calls/update_application.j2

@ -0,0 +1 @@
create_application.j2

1
templates/api-calls/update_application_plan.j2

@ -0,0 +1 @@
create_application_plan.j2

1
templates/api-calls/update_mapping_rule.j2

@ -0,0 +1 @@
create_mapping_rule.j2

1
templates/api-calls/update_method.j2

@ -0,0 +1 @@
create_method.j2

20
templates/api-calls/update_proxy.j2

@ -0,0 +1,20 @@
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'credentials_location=' ~ threescale_cicd_api_credentials_location|urlencode,
'api_backend=' ~ threescale_cicd_private_base_url|urlencode
]
%}
{% if threescale_cicd_api_security_scheme.type == 'apiKey' %}
{% do payload.append('auth_user_key=' ~ threescale_cicd_api_security_scheme.name|urlencode) %}
{% endif %}
{% if threescale_cicd_api_security_scheme.type == 'oauth2' %}
{% do payload.append('oidc_issuer_endpoint=' ~ threescale_cicd_sso_issuer_endpoint|urlencode) %}
{% endif %}
{% if threescale_cicd_apicast_sandbox_endpoint is defined %}
{% do payload.append('sandbox_endpoint=' ~ threescale_cicd_apicast_sandbox_endpoint|urlencode) %}
{% endif %}
{% if threescale_cicd_apicast_production_endpoint is defined %}
{% do payload.append('endpoint=' ~ threescale_cicd_apicast_production_endpoint|urlencode) %}
{% endif %}
{{ payload|join("&") }}

1
templates/api-calls/update_service.j2

@ -0,0 +1 @@
create_service.j2

5
templates/existing_mapping_rules.j2

@ -0,0 +1,5 @@
{% set mapping_rules = {} %}
{% for value in threescale_cicd_existing_mapping_rules_details %}
{% do mapping_rules.update({ (threescale_cicd_existing_metrics_details|selectattr("id", "equalto", value.metric_id)|first).system_name: value.id }) %}
{% endfor %}
{{ mapping_rules }}

7
templates/metrics_to_delete.j2

@ -0,0 +1,7 @@
{% set to_delete = [] %}
{% for metric in threescale_cicd_existing_metrics_details %}
{% if metric.system_name != "hits" and metric.system_name not in threescale_cicd_api_operations %}
{% do to_delete.append(metric) %}
{% endif %}
{% endfor %}
{{ to_delete }}

22
templates/rewritten_openapi.j2

@ -0,0 +1,22 @@
{% set security_definitions = threescale_cicd_api_security_definitions %}
{% set new_openapi = threescale_cicd_openapi_file_content %}
{# Add the RH-SSO endpoints to the OpenAPI securityDefinitions #}
{% if threescale_cicd_api_security_scheme.type == "oauth2" %}
{% do security_definitions[threescale_cicd_api_security_scheme_name].update({ "authorizationUrl": threescale_cicd_sso_realm_endpoint ~ "/protocol/openid-connect/auth", "tokenUrl": threescale_cicd_sso_realm_endpoint ~ "/protocol/openid-connect/token" }) %}
{% endif %}
{# Add the RH-SSO default scope to the OpenAPI securityDefinitions #}
{% if threescale_cicd_api_security_scheme.type == "oauth2" and "scopes" not in threescale_cicd_api_security_scheme %}
{% do security_definitions[threescale_cicd_api_security_scheme_name].update({ "scopes": threescale_cicd_default_oauth_scopes }) %}
{% endif %}
{# Update the security definitions #}
{% do new_openapi.update({ "securityDefinitions": security_definitions }) %}
{# 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_hostname = threescale_cicd_apicast_production_endpoint|urlsplit('hostname') %}
{% do new_openapi.update({
"schemes": [ apicast_production_scheme ],
"host": apicast_production_hostname
}) %}
{# Make sure the swagger version is a string and not a number #}
{% do new_openapi.update({ "swagger": new_openapi.swagger ~ "" }) %}
{{ new_openapi }}

5
templates/wanted_mapping_rules.j2

@ -0,0 +1,5 @@
{% set mapping_rules = {} %}
{% for key, value in threescale_cicd_api_operations.items() %}
{% do mapping_rules.update({ key: { "http_method": value.verb.upper(), "pattern": threescale_cicd_api_basepath ~ value.path ~ "$", "delta": 1 } }) %}
{% endfor %}
{{ mapping_rules }}

63
vars/main.yml

@ -0,0 +1,63 @@
---
# Credentials are expected to be passed in HTTP headers unless stated otherwise
# and only for API Keys
threescale_cicd_api_credentials_location: '{{ ''headers'' if threescale_cicd_api_security_scheme.in|default(''header'') == ''header'' or threescale_cicd_api_security_scheme.type == ''oauth2'' else ''query'' }}'
# A list of unused metrics to delete
threescale_cicd_metrics_to_delete: '{{ lookup(''template'', ''metrics_to_delete.j2'') }}'
# The OpenAPI file to be pushed to 3scale as an ActiveDocs
threescale_cicd_openapi_rewritten: '{{ lookup(''template'', ''rewritten_openapi.j2'') }}'
##
## ID Lookup Variables
##
# The id of the current service is fetched from the threescale_cicd_existing_services_details fact
threescale_cicd_api_service_id: '{{ (threescale_cicd_existing_services_details|selectattr(''system_name'', ''equalto'', threescale_cicd_api_system_name)|first)[''id''] }}'
# The id of the 'hits' metric is fetched from the threescale_cicd_existing_metrics_details fact
threescale_cicd_metric_id: '{{ (threescale_cicd_existing_metrics_details|selectattr(''system_name'', ''equalto'', ''hits'')|first).id }}'
# Find the default application plan id from its system name
threescale_cicd_default_application_plan_id: '{{ (threescale_cicd_existing_application_plans_details|selectattr("system_name", "equalto", threescale_cicd_default_application_plan)|first).id }}'
# Find the id of the existing activedocs from the threescale_cicd_existing_activedocs_details fact
threescale_cicd_api_activedocs_id: '{{ (threescale_cicd_existing_activedocs_details|selectattr(''system_name'', ''equalto'', threescale_cicd_api_system_name)|first).id }}'
##
## Mapping Rules computation
##
# what we want
threescale_cicd_wanted_mapping_rules: '{{ lookup(''template'', ''wanted_mapping_rules.j2'') }}'
# what we have
threescale_cicd_existing_mapping_rules: '{{ lookup(''template'', ''existing_mapping_rules.j2'') }}'
# create the items that we want but don't have yet
threescale_cicd_mapping_rules_to_create: '{{ threescale_cicd_wanted_mapping_rules.keys()|difference(threescale_cicd_existing_mapping_rules.keys()) }}'
# delete the items that we don't want but we have
threescale_cicd_mapping_rules_to_delete: '{{ threescale_cicd_existing_mapping_rules.keys()|difference(threescale_cicd_wanted_mapping_rules.keys()) }}'
# update the items that we want and we have
threescale_cicd_mapping_rules_to_update: '{{ threescale_cicd_existing_mapping_rules.keys()|intersect(threescale_cicd_wanted_mapping_rules.keys()) }}'
##
## 3scale API Payload definition
##
threescale_cicd_update_proxy_payload: '{{ lookup(''template'', ''api-calls/update_proxy.j2'') }}'
threescale_cicd_update_service_payload: '{{ lookup(''template'', ''api-calls/update_service.j2'') }}'
threescale_cicd_create_service_payload: '{{ lookup(''template'', ''api-calls/create_service.j2'') }}'
threescale_cicd_update_method_payload: '{{ lookup(''template'', ''api-calls/update_method.j2'') }}'
threescale_cicd_create_method_payload: '{{ lookup(''template'', ''api-calls/create_method.j2'') }}'
threescale_cicd_update_mapping_rule_payload: '{{ lookup(''template'', ''api-calls/update_mapping_rule.j2'') }}'
threescale_cicd_create_mapping_rule_payload: '{{ lookup(''template'', ''api-calls/create_mapping_rule.j2'') }}'
threescale_cicd_update_application_plan_payload: '{{ lookup(''template'', ''api-calls/update_application_plan.j2'') }}'
threescale_cicd_create_application_plan_payload: '{{ lookup(''template'', ''api-calls/create_application_plan.j2'') }}'
threescale_cicd_find_application_payload: '{{ lookup(''template'', ''api-calls/find_application.j2'') }}'
threescale_cicd_update_application_payload: '{{ lookup(''template'', ''api-calls/update_application.j2'') }}'
threescale_cicd_create_application_payload: '{{ lookup(''template'', ''api-calls/create_application.j2'') }}'
threescale_cicd_authenticate_to_keycloak_payload: '{{ lookup(''template'', ''api-calls/keycloak/authenticate.j2'') }}'
threescale_cicd_patch_keycloak_client_payload: '{{ lookup(''template'', ''api-calls/keycloak/patch_client.j2'') }}'
threescale_cicd_smoke_test_headers: '{{ lookup(''template'', ''api-calls/smoke-test/headers.j2'') }}'
threescale_cicd_smoke_test_url: '{{ lookup(''template'', ''api-calls/smoke-test/url.j2'') }}'
threescale_cicd_promote_proxy_payload: '{{ lookup(''template'', ''api-calls/promote_proxy.j2'') }}'
threescale_cicd_update_activedoc_payload: '{{ lookup(''template'', ''api-calls/update_activedoc.j2'') }}'
threescale_cicd_create_activedoc_payload: '{{ lookup(''template'', ''api-calls/create_activedoc.j2'') }}'
Loading…
Cancel
Save