From 8f8ec50d357ffb00ab1ed82803fe85458f074b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Wed, 22 Aug 2018 17:27:05 +0200 Subject: [PATCH] See #22: reorganize this role so that it use variables where possible (instead of facts) --- ansible.cfg | 2 + defaults/main.yml | 20 ++- tasks/api-calls/create_activedoc.yml | 23 +++ tasks/api-calls/create_application.yml | 21 +++ tasks/api-calls/create_application_plan.yml | 22 +++ tasks/api-calls/create_mapping_rule.yml | 19 +++ tasks/api-calls/create_method.yml | 23 +++ tasks/api-calls/create_service.yml | 24 +++ tasks/api-calls/delete_mapping_rule.yml | 14 ++ tasks/api-calls/delete_metric.yml | 17 +++ tasks/api-calls/find_application.yml | 13 ++ tasks/api-calls/find_first_account.yml | 10 ++ tasks/api-calls/get_proxy_version.yml | 20 +++ tasks/api-calls/keycloak/authenticate.yml | 22 +++ tasks/api-calls/keycloak/patch_client.yml | 21 +++ tasks/api-calls/keycloak/wait_for_client.yml | 18 +++ tasks/api-calls/promote_proxy.yml | 17 +++ tasks/api-calls/smoke_test.yml | 20 +++ tasks/api-calls/update_activedoc.yml | 19 +++ tasks/api-calls/update_application.yml | 21 +++ tasks/api-calls/update_application_plan.yml | 18 +++ tasks/api-calls/update_mapping_rule.yml | 21 +++ tasks/api-calls/update_method.yml | 18 +++ tasks/api-calls/update_proxy.yml | 28 ++++ tasks/api-calls/update_service.yml | 19 +++ tasks/check_requirements.yml | 32 ---- tasks/create_activedocs.yml | 113 -------------- tasks/create_application_plans.yml | 38 ----- tasks/create_default_application.yml | 89 ----------- tasks/create_mapping_rule.yml | 28 ---- tasks/create_service.yml | 58 ------- tasks/delete_unused_metrics.yml | 25 --- tasks/main.yml | 142 ++++-------------- tasks/patch_default_application_for_oauth.yml | 65 -------- tasks/promote.yml | 42 ------ tasks/smoke_tests.yml | 59 -------- tasks/smoke_tests_apikey.yml | 9 -- tasks/smoke_tests_oauth.yml | 36 ----- tasks/steps/activedoc.yml | 9 ++ tasks/steps/application_plan.yml | 8 + tasks/steps/application_plans.yml | 6 + tasks/steps/cleanup_metrics.yml | 6 + tasks/steps/default_application.yml | 33 ++++ tasks/steps/discover.yml | 47 ++++++ tasks/steps/mapping_rules.yml | 25 +++ tasks/steps/method.yml | 7 + tasks/steps/methods.yml | 16 ++ tasks/steps/promote.yml | 6 + tasks/steps/proxy.yml | 3 + .../read_openapi.yml} | 9 ++ tasks/steps/requirements.yml | 57 +++++++ tasks/steps/service.yml | 7 + tasks/steps/smoke_test.yml | 14 ++ tasks/steps/variables_from_inventory.yml | 26 ++++ tasks/update_mapping_rule.yml | 30 ---- tasks/update_mapping_rules.yml | 59 -------- tasks/update_method.yml | 47 ------ tasks/update_metrics.yml | 20 --- tasks/update_proxy.yml | 23 --- templates/api-calls/create_activedoc.j2 | 11 ++ templates/api-calls/create_application.j2 | 15 ++ .../api-calls/create_application_plan.j2 | 9 ++ templates/api-calls/create_mapping_rule.j2 | 10 ++ templates/api-calls/create_method.j2 | 10 ++ templates/api-calls/create_service.j2 | 10 ++ templates/api-calls/find_application.j2 | 7 + templates/api-calls/keycloak/authenticate.j2 | 5 + templates/api-calls/keycloak/patch_client.j2 | 1 + templates/api-calls/promote_proxy.j2 | 1 + templates/api-calls/smoke-test/headers.j2 | 8 + templates/api-calls/smoke-test/url.j2 | 10 ++ templates/api-calls/update_activedoc.j2 | 1 + templates/api-calls/update_application.j2 | 1 + .../api-calls/update_application_plan.j2 | 1 + templates/api-calls/update_mapping_rule.j2 | 1 + templates/api-calls/update_method.j2 | 1 + templates/api-calls/update_proxy.j2 | 20 +++ templates/api-calls/update_service.j2 | 1 + templates/existing_mapping_rules.j2 | 5 + templates/metrics_to_delete.j2 | 7 + templates/rewritten_openapi.j2 | 22 +++ templates/wanted_mapping_rules.j2 | 5 + vars/main.yml | 63 ++++++++ 83 files changed, 998 insertions(+), 891 deletions(-) create mode 100644 ansible.cfg create mode 100644 tasks/api-calls/create_activedoc.yml create mode 100644 tasks/api-calls/create_application.yml create mode 100644 tasks/api-calls/create_application_plan.yml create mode 100644 tasks/api-calls/create_mapping_rule.yml create mode 100644 tasks/api-calls/create_method.yml create mode 100644 tasks/api-calls/create_service.yml create mode 100644 tasks/api-calls/delete_mapping_rule.yml create mode 100644 tasks/api-calls/delete_metric.yml create mode 100644 tasks/api-calls/find_application.yml create mode 100644 tasks/api-calls/find_first_account.yml create mode 100644 tasks/api-calls/get_proxy_version.yml create mode 100644 tasks/api-calls/keycloak/authenticate.yml create mode 100644 tasks/api-calls/keycloak/patch_client.yml create mode 100644 tasks/api-calls/keycloak/wait_for_client.yml create mode 100644 tasks/api-calls/promote_proxy.yml create mode 100644 tasks/api-calls/smoke_test.yml create mode 100644 tasks/api-calls/update_activedoc.yml create mode 100644 tasks/api-calls/update_application.yml create mode 100644 tasks/api-calls/update_application_plan.yml create mode 100644 tasks/api-calls/update_mapping_rule.yml create mode 100644 tasks/api-calls/update_method.yml create mode 100644 tasks/api-calls/update_proxy.yml create mode 100644 tasks/api-calls/update_service.yml delete mode 100644 tasks/check_requirements.yml delete mode 100644 tasks/create_activedocs.yml delete mode 100644 tasks/create_application_plans.yml delete mode 100644 tasks/create_default_application.yml delete mode 100644 tasks/create_mapping_rule.yml delete mode 100644 tasks/create_service.yml delete mode 100644 tasks/delete_unused_metrics.yml delete mode 100644 tasks/patch_default_application_for_oauth.yml delete mode 100644 tasks/promote.yml delete mode 100644 tasks/smoke_tests.yml delete mode 100644 tasks/smoke_tests_apikey.yml delete mode 100644 tasks/smoke_tests_oauth.yml create mode 100644 tasks/steps/activedoc.yml create mode 100644 tasks/steps/application_plan.yml create mode 100644 tasks/steps/application_plans.yml create mode 100644 tasks/steps/cleanup_metrics.yml create mode 100644 tasks/steps/default_application.yml create mode 100644 tasks/steps/discover.yml create mode 100644 tasks/steps/mapping_rules.yml create mode 100644 tasks/steps/method.yml create mode 100644 tasks/steps/methods.yml create mode 100644 tasks/steps/promote.yml create mode 100644 tasks/steps/proxy.yml rename tasks/{read_openapi_file.yml => steps/read_openapi.yml} (96%) create mode 100644 tasks/steps/requirements.yml create mode 100644 tasks/steps/service.yml create mode 100644 tasks/steps/smoke_test.yml create mode 100644 tasks/steps/variables_from_inventory.yml delete mode 100644 tasks/update_mapping_rule.yml delete mode 100644 tasks/update_mapping_rules.yml delete mode 100644 tasks/update_method.yml delete mode 100644 tasks/update_metrics.yml delete mode 100644 tasks/update_proxy.yml create mode 100644 templates/api-calls/create_activedoc.j2 create mode 100644 templates/api-calls/create_application.j2 create mode 100644 templates/api-calls/create_application_plan.j2 create mode 100644 templates/api-calls/create_mapping_rule.j2 create mode 100644 templates/api-calls/create_method.j2 create mode 100644 templates/api-calls/create_service.j2 create mode 100644 templates/api-calls/find_application.j2 create mode 100644 templates/api-calls/keycloak/authenticate.j2 create mode 100644 templates/api-calls/keycloak/patch_client.j2 create mode 100644 templates/api-calls/promote_proxy.j2 create mode 100644 templates/api-calls/smoke-test/headers.j2 create mode 100644 templates/api-calls/smoke-test/url.j2 create mode 120000 templates/api-calls/update_activedoc.j2 create mode 120000 templates/api-calls/update_application.j2 create mode 120000 templates/api-calls/update_application_plan.j2 create mode 120000 templates/api-calls/update_mapping_rule.j2 create mode 120000 templates/api-calls/update_method.j2 create mode 100644 templates/api-calls/update_proxy.j2 create mode 120000 templates/api-calls/update_service.j2 create mode 100644 templates/existing_mapping_rules.j2 create mode 100644 templates/metrics_to_delete.j2 create mode 100644 templates/rewritten_openapi.j2 create mode 100644 templates/wanted_mapping_rules.j2 create mode 100644 vars/main.yml diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..fc43e98 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +jinja2_extensions = jinja2.ext.do diff --git a/defaults/main.yml b/defaults/main.yml index 60969d2..7defd55 100644 --- a/defaults/main.yml +++ b/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'') }}' diff --git a/tasks/api-calls/create_activedoc.yml b/tasks/api-calls/create_activedoc.yml new file mode 100644 index 0000000..ca366bc --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/create_application.yml b/tasks/api-calls/create_application.yml new file mode 100644 index 0000000..d5cb399 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/create_application_plan.yml b/tasks/api-calls/create_application_plan.yml new file mode 100644 index 0000000..01e6a86 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/create_mapping_rule.yml b/tasks/api-calls/create_mapping_rule.yml new file mode 100644 index 0000000..13c32e3 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/create_method.yml b/tasks/api-calls/create_method.yml new file mode 100644 index 0000000..db4285b --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/create_service.yml b/tasks/api-calls/create_service.yml new file mode 100644 index 0000000..33f2ca7 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/delete_mapping_rule.yml b/tasks/api-calls/delete_mapping_rule.yml new file mode 100644 index 0000000..efbe168 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/delete_metric.yml b/tasks/api-calls/delete_metric.yml new file mode 100644 index 0000000..fe7898a --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/find_application.yml b/tasks/api-calls/find_application.yml new file mode 100644 index 0000000..6ed39e6 --- /dev/null +++ b/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' diff --git a/tasks/api-calls/find_first_account.yml b/tasks/api-calls/find_first_account.yml new file mode 100644 index 0000000..5726d05 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/get_proxy_version.yml b/tasks/api-calls/get_proxy_version.yml new file mode 100644 index 0000000..88bbc6e --- /dev/null +++ b/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'' }}' diff --git a/tasks/api-calls/keycloak/authenticate.yml b/tasks/api-calls/keycloak/authenticate.yml new file mode 100644 index 0000000..e9b3995 --- /dev/null +++ b/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") }}' diff --git a/tasks/api-calls/keycloak/patch_client.yml b/tasks/api-calls/keycloak/patch_client.yml new file mode 100644 index 0000000..21e4516 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/keycloak/wait_for_client.yml b/tasks/api-calls/keycloak/wait_for_client.yml new file mode 100644 index 0000000..e6d764e --- /dev/null +++ b/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] }}' diff --git a/tasks/api-calls/promote_proxy.yml b/tasks/api-calls/promote_proxy.yml new file mode 100644 index 0000000..7ad6199 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/smoke_test.yml b/tasks/api-calls/smoke_test.yml new file mode 100644 index 0000000..c0afa49 --- /dev/null +++ b/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' diff --git a/tasks/api-calls/update_activedoc.yml b/tasks/api-calls/update_activedoc.yml new file mode 100644 index 0000000..0cbfd17 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_application.yml b/tasks/api-calls/update_application.yml new file mode 100644 index 0000000..8bd9901 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_application_plan.yml b/tasks/api-calls/update_application_plan.yml new file mode 100644 index 0000000..346ed42 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_mapping_rule.yml b/tasks/api-calls/update_mapping_rule.yml new file mode 100644 index 0000000..483d27e --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_method.yml b/tasks/api-calls/update_method.yml new file mode 100644 index 0000000..5247b02 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_proxy.yml b/tasks/api-calls/update_proxy.yml new file mode 100644 index 0000000..81d3687 --- /dev/null +++ b/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 }}' diff --git a/tasks/api-calls/update_service.yml b/tasks/api-calls/update_service.yml new file mode 100644 index 0000000..98c6909 --- /dev/null +++ b/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 }}' diff --git a/tasks/check_requirements.yml b/tasks/check_requirements.yml deleted file mode 100644 index 6e44c93..0000000 --- a/tasks/check_requirements.yml +++ /dev/null @@ -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'." diff --git a/tasks/create_activedocs.yml b/tasks/create_activedocs.yml deleted file mode 100644 index 9c0fee8..0000000 --- a/tasks/create_activedocs.yml +++ /dev/null @@ -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' diff --git a/tasks/create_application_plans.yml b/tasks/create_application_plans.yml deleted file mode 100644 index c0e53ac..0000000 --- a/tasks/create_application_plans.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/create_default_application.yml b/tasks/create_default_application.yml deleted file mode 100644 index efb51fc..0000000 --- a/tasks/create_default_application.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/create_mapping_rule.yml b/tasks/create_mapping_rule.yml deleted file mode 100644 index f6fa095..0000000 --- a/tasks/create_mapping_rule.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/create_service.yml b/tasks/create_service.yml deleted file mode 100644 index 3da7932..0000000 --- a/tasks/create_service.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/delete_unused_metrics.yml b/tasks/delete_unused_metrics.yml deleted file mode 100644 index 10424c2..0000000 --- a/tasks/delete_unused_metrics.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/main.yml b/tasks/main.yml index f9498a7..14d31e8 100644 --- a/tasks/main.yml +++ b/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 diff --git a/tasks/patch_default_application_for_oauth.yml b/tasks/patch_default_application_for_oauth.yml deleted file mode 100644 index c5743e5..0000000 --- a/tasks/patch_default_application_for_oauth.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/promote.yml b/tasks/promote.yml deleted file mode 100644 index 76fcc79..0000000 --- a/tasks/promote.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/smoke_tests.yml b/tasks/smoke_tests.yml deleted file mode 100644 index 356107a..0000000 --- a/tasks/smoke_tests.yml +++ /dev/null @@ -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' diff --git a/tasks/smoke_tests_apikey.yml b/tasks/smoke_tests_apikey.yml deleted file mode 100644 index b6c1ed8..0000000 --- a/tasks/smoke_tests_apikey.yml +++ /dev/null @@ -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"' diff --git a/tasks/smoke_tests_oauth.yml b/tasks/smoke_tests_oauth.yml deleted file mode 100644 index 94b792c..0000000 --- a/tasks/smoke_tests_oauth.yml +++ /dev/null @@ -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 }) }}" diff --git a/tasks/steps/activedoc.yml b/tasks/steps/activedoc.yml new file mode 100644 index 0000000..dfa531e --- /dev/null +++ b/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' diff --git a/tasks/steps/application_plan.yml b/tasks/steps/application_plan.yml new file mode 100644 index 0000000..0953092 --- /dev/null +++ b/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' + diff --git a/tasks/steps/application_plans.yml b/tasks/steps/application_plans.yml new file mode 100644 index 0000000..2607a7f --- /dev/null +++ b/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 diff --git a/tasks/steps/cleanup_metrics.yml b/tasks/steps/cleanup_metrics.yml new file mode 100644 index 0000000..08a9ab0 --- /dev/null +++ b/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 diff --git a/tasks/steps/default_application.yml b/tasks/steps/default_application.yml new file mode 100644 index 0000000..4de5a08 --- /dev/null +++ b/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''' diff --git a/tasks/steps/discover.yml b/tasks/steps/discover.yml new file mode 100644 index 0000000..d795609 --- /dev/null +++ b/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 diff --git a/tasks/steps/mapping_rules.yml b/tasks/steps/mapping_rules.yml new file mode 100644 index 0000000..299cbe7 --- /dev/null +++ b/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 diff --git a/tasks/steps/method.yml b/tasks/steps/method.yml new file mode 100644 index 0000000..cd7911e --- /dev/null +++ b/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' diff --git a/tasks/steps/methods.yml b/tasks/steps/methods.yml new file mode 100644 index 0000000..abb9db8 --- /dev/null +++ b/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 diff --git a/tasks/steps/promote.yml b/tasks/steps/promote.yml new file mode 100644 index 0000000..daf8d79 --- /dev/null +++ b/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' diff --git a/tasks/steps/proxy.yml b/tasks/steps/proxy.yml new file mode 100644 index 0000000..9a9ae13 --- /dev/null +++ b/tasks/steps/proxy.yml @@ -0,0 +1,3 @@ +--- + +- import_tasks: api-calls/update_proxy.yml diff --git a/tasks/read_openapi_file.yml b/tasks/steps/read_openapi.yml similarity index 96% rename from tasks/read_openapi_file.yml rename to tasks/steps/read_openapi.yml index 3fe784f..ace597c 100644 --- a/tasks/read_openapi_file.yml +++ b/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 }}" diff --git a/tasks/steps/requirements.yml b/tasks/steps/requirements.yml new file mode 100644 index 0000000..f0bf946 --- /dev/null +++ b/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 diff --git a/tasks/steps/service.yml b/tasks/steps/service.yml new file mode 100644 index 0000000..4a58bf6 --- /dev/null +++ b/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' diff --git a/tasks/steps/smoke_test.yml b/tasks/steps/smoke_test.yml new file mode 100644 index 0000000..aaa181a --- /dev/null +++ b/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 diff --git a/tasks/steps/variables_from_inventory.yml b/tasks/steps/variables_from_inventory.yml new file mode 100644 index 0000000..fe73302 --- /dev/null +++ b/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' diff --git a/tasks/update_mapping_rule.yml b/tasks/update_mapping_rule.yml deleted file mode 100644 index a11a965..0000000 --- a/tasks/update_mapping_rule.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/update_mapping_rules.yml b/tasks/update_mapping_rules.yml deleted file mode 100644 index 00d2cc8..0000000 --- a/tasks/update_mapping_rules.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/update_method.yml b/tasks/update_method.yml deleted file mode 100644 index 19e1d93..0000000 --- a/tasks/update_method.yml +++ /dev/null @@ -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 }}' diff --git a/tasks/update_metrics.yml b/tasks/update_metrics.yml deleted file mode 100644 index 7c2ff6c..0000000 --- a/tasks/update_metrics.yml +++ /dev/null @@ -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 diff --git a/tasks/update_proxy.yml b/tasks/update_proxy.yml deleted file mode 100644 index 34d4d13..0000000 --- a/tasks/update_proxy.yml +++ /dev/null @@ -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 }}' diff --git a/templates/api-calls/create_activedoc.j2 b/templates/api-calls/create_activedoc.j2 new file mode 100644 index 0000000..1c38736 --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/create_application.j2 b/templates/api-calls/create_application.j2 new file mode 100644 index 0000000..4d7acf6 --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/create_application_plan.j2 b/templates/api-calls/create_application_plan.j2 new file mode 100644 index 0000000..105d20e --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/create_mapping_rule.j2 b/templates/api-calls/create_mapping_rule.j2 new file mode 100644 index 0000000..a7398fd --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/create_method.j2 b/templates/api-calls/create_method.j2 new file mode 100644 index 0000000..c08ba83 --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/create_service.j2 b/templates/api-calls/create_service.j2 new file mode 100644 index 0000000..4343a25 --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/find_application.j2 b/templates/api-calls/find_application.j2 new file mode 100644 index 0000000..b2dec63 --- /dev/null +++ b/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 -%} \ No newline at end of file diff --git a/templates/api-calls/keycloak/authenticate.j2 b/templates/api-calls/keycloak/authenticate.j2 new file mode 100644 index 0000000..52ffe49 --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/keycloak/patch_client.j2 b/templates/api-calls/keycloak/patch_client.j2 new file mode 100644 index 0000000..1721809 --- /dev/null +++ b/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 }) }} diff --git a/templates/api-calls/promote_proxy.j2 b/templates/api-calls/promote_proxy.j2 new file mode 100644 index 0000000..e1f60ae --- /dev/null +++ b/templates/api-calls/promote_proxy.j2 @@ -0,0 +1 @@ +access_token={{ threescale_cicd_access_token|urlencode }}&to={{ threescale_cicd_production_environment_name|urlencode }} \ No newline at end of file diff --git a/templates/api-calls/smoke-test/headers.j2 b/templates/api-calls/smoke-test/headers.j2 new file mode 100644 index 0000000..d03e293 --- /dev/null +++ b/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 }} \ No newline at end of file diff --git a/templates/api-calls/smoke-test/url.j2 b/templates/api-calls/smoke-test/url.j2 new file mode 100644 index 0000000..e19414e --- /dev/null +++ b/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 -%} \ No newline at end of file diff --git a/templates/api-calls/update_activedoc.j2 b/templates/api-calls/update_activedoc.j2 new file mode 120000 index 0000000..bd584b4 --- /dev/null +++ b/templates/api-calls/update_activedoc.j2 @@ -0,0 +1 @@ +create_activedoc.j2 \ No newline at end of file diff --git a/templates/api-calls/update_application.j2 b/templates/api-calls/update_application.j2 new file mode 120000 index 0000000..036dd22 --- /dev/null +++ b/templates/api-calls/update_application.j2 @@ -0,0 +1 @@ +create_application.j2 \ No newline at end of file diff --git a/templates/api-calls/update_application_plan.j2 b/templates/api-calls/update_application_plan.j2 new file mode 120000 index 0000000..3712a75 --- /dev/null +++ b/templates/api-calls/update_application_plan.j2 @@ -0,0 +1 @@ +create_application_plan.j2 \ No newline at end of file diff --git a/templates/api-calls/update_mapping_rule.j2 b/templates/api-calls/update_mapping_rule.j2 new file mode 120000 index 0000000..f03cd71 --- /dev/null +++ b/templates/api-calls/update_mapping_rule.j2 @@ -0,0 +1 @@ +create_mapping_rule.j2 \ No newline at end of file diff --git a/templates/api-calls/update_method.j2 b/templates/api-calls/update_method.j2 new file mode 120000 index 0000000..7969ddb --- /dev/null +++ b/templates/api-calls/update_method.j2 @@ -0,0 +1 @@ +create_method.j2 \ No newline at end of file diff --git a/templates/api-calls/update_proxy.j2 b/templates/api-calls/update_proxy.j2 new file mode 100644 index 0000000..9c927bd --- /dev/null +++ b/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("&") }} \ No newline at end of file diff --git a/templates/api-calls/update_service.j2 b/templates/api-calls/update_service.j2 new file mode 120000 index 0000000..baa93b9 --- /dev/null +++ b/templates/api-calls/update_service.j2 @@ -0,0 +1 @@ +create_service.j2 \ No newline at end of file diff --git a/templates/existing_mapping_rules.j2 b/templates/existing_mapping_rules.j2 new file mode 100644 index 0000000..79ae498 --- /dev/null +++ b/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 }} \ No newline at end of file diff --git a/templates/metrics_to_delete.j2 b/templates/metrics_to_delete.j2 new file mode 100644 index 0000000..d7c2047 --- /dev/null +++ b/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 }} \ No newline at end of file diff --git a/templates/rewritten_openapi.j2 b/templates/rewritten_openapi.j2 new file mode 100644 index 0000000..87614fb --- /dev/null +++ b/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 }} \ No newline at end of file diff --git a/templates/wanted_mapping_rules.j2 b/templates/wanted_mapping_rules.j2 new file mode 100644 index 0000000..45e9ac8 --- /dev/null +++ b/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 }} \ No newline at end of file diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..f29b530 --- /dev/null +++ b/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'') }}'