From 629ce9d1f99c26b33448aa28d0d5865c0ed3319c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Tue, 24 Apr 2018 16:50:45 +0200 Subject: [PATCH] minor fixes + publish activedocs --- defaults/main.yml | 2 + tasks/create_activedocs.yml | 92 ++++++++++++++++++++++++++++ tasks/main.yml | 13 ++-- tasks/read_openapi_file.yml | 15 +++-- tasks/retrieve_existing_services.yml | 11 ---- 5 files changed, 113 insertions(+), 20 deletions(-) create mode 100644 tasks/create_activedocs.yml delete mode 100644 tasks/retrieve_existing_services.yml diff --git a/defaults/main.yml b/defaults/main.yml index c1475af..e862117 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -6,3 +6,5 @@ threescale_cicd_default_application_name: 'Ansible smoke-tests default applicati 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_oauth_scopes: + openid: Any OpenID Connect token diff --git a/tasks/create_activedocs.yml b/tasks/create_activedocs.yml new file mode 100644 index 0000000..874a733 --- /dev/null +++ b/tasks/create_activedocs.yml @@ -0,0 +1,92 @@ +--- + +- 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: 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 + +- name: Update the ActiveDocs + uri: + url: https://{{ inventory_hostname }}/admin/api/active_docs/{{ (threescale_cicd_existing_activedocs_details|selectattr('system_name', 'equalto', threescale_cicd_api_system_name)|first).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' diff --git a/tasks/main.yml b/tasks/main.yml index cd1e6d1..dee2d70 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -15,6 +15,11 @@ 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 inventory + set_fact: + threescale_cicd_sso_realm_endpoint: '{{ (hostvars[groups[''sso''][0]].scheme|default(''https'')) ~ ''://'' ~ groups[''sso''][0] ~ ''/auth/realms/'' ~ hostvars[groups[''sso''][0]].realm }}' + when: 'threescale_cicd_sso_realm_endpoint is not defined and ''sso'' in groups and groups[''sso''] > 0' + - 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] }}' @@ -28,9 +33,6 @@ # Load the API definition from the provided OpenAPI file - import_tasks: read_openapi_file.yml -# Retrieve existing services from the 3scale Admin Portal -- import_tasks: retrieve_existing_services.yml - - name: Compute the service system_name set_fact: threescale_cicd_api_system_name: '{{ threescale_cicd_api_environment_name ~ "_" ~ threescale_cicd_api_system_name }}' @@ -68,7 +70,7 @@ - set_fact: threescale_cicd_api_proxy_definition: credentials_location: '{{ threescale_cicd_api_credentials_location }}' - api_backend: '{{ threescale_cicd_api_backend_scheme ~ ''://'' ~ threescale_cicd_api_backend_hostname }}' + 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 }) }}' @@ -124,3 +126,6 @@ # Delete the metrics that are not needed anymore - import_tasks: delete_unused_metrics.yml + +# Publish the OpenAPI Specifications file on the 3scale Admin Portal +- import_tasks: create_activedocs.yml diff --git a/tasks/read_openapi_file.yml b/tasks/read_openapi_file.yml index f55f4ac..e2c013b 100644 --- a/tasks/read_openapi_file.yml +++ b/tasks/read_openapi_file.yml @@ -23,6 +23,7 @@ - name: Extract API Methods set_fact: threescale_cicd_api_name: '{{ threescale_cicd_openapi_file_content.info.title|default("API") }}' + threescale_cicd_api_description: '{{ threescale_cicd_openapi_file_content.info.description|default("") }}' threescale_cicd_api_basepath: '{{ threescale_cicd_openapi_file_content.basePath|default("") }}' threescale_cicd_api_operations: >- {% set operations = {} -%} @@ -64,7 +65,7 @@ - name: Extract the security definitions and requirements from OpenAPI set_fact: - threescale_cicd_api_security_requirements: '{{ threescale_cicd_openapi_file_content.security|default({}) }}' + threescale_cicd_api_security_requirements: '{{ threescale_cicd_openapi_file_content.security|default([]) }}' threescale_cicd_api_security_definitions: '{{ threescale_cicd_openapi_file_content.securityDefinitions|default({}) }}' - name: Make sure there is one and exactly one security requirement @@ -75,16 +76,16 @@ - name: Find the security requirement to use set_fact: - threescale_cicd_api_security_scheme: '{{ threescale_cicd_api_security_requirements.keys()[0] }}' + threescale_cicd_api_security_scheme_name: '{{ threescale_cicd_api_security_requirements[0].keys()[0] }}' - name: Make sure the requested security definition exists assert: that: - - 'threescale_cicd_api_security_scheme in threescale_cicd_api_security_definitions' + - 'threescale_cicd_api_security_scheme_name in threescale_cicd_api_security_definitions' - name: Find the security definition to use set_fact: - threescale_cicd_api_security_scheme: '{{ threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme] }}' + threescale_cicd_api_security_scheme: '{{ threescale_cicd_api_security_definitions[threescale_cicd_api_security_scheme_name] }}' - name: Make sure the security scheme is consistent with 3scale assert: @@ -111,13 +112,17 @@ threescale_cicd_api_backend_scheme: '{{ threescale_cicd_openapi_file_content.schemes|default(["http"])|first }}' when: 'threescale_cicd_api_backend_scheme is not defined' +- name: Compute the private base url from the OpenAPI file + set_fact: + threescale_cicd_private_base_url: '{{ threescale_cicd_api_backend_scheme ~ ''://'' ~ threescale_cicd_api_backend_hostname }}' + when: 'threescale_cicd_private_base_url is not defined' + - assert: that: - 'threescale_cicd_api_backend_scheme is defined' - 'threescale_cicd_api_backend_hostname is defined' msg: 'The backend hostname and scheme must either be in the swagger or declared as extra variables (threescale_cicd_api_backend_scheme / threescale_cicd_api_backend_hostname)' - - name: Find the smoke-test flagged operation set_fact: threescale_cicd_openapi_smoketest_operation: '{{ threescale_cicd_openapi_file_content|json_query(''paths.*.get[? "x-threescale-smoketests-operation" ].operationId|[0]'') }}' diff --git a/tasks/retrieve_existing_services.yml b/tasks/retrieve_existing_services.yml deleted file mode 100644 index 1da9686..0000000 --- a/tasks/retrieve_existing_services.yml +++ /dev/null @@ -1,11 +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}'') }}'