diff --git a/ansible/playbooks/3scale.yml b/ansible/playbooks/3scale.yml new file mode 100644 index 00000000..cf3744cc --- /dev/null +++ b/ansible/playbooks/3scale.yml @@ -0,0 +1,30 @@ +--- + +- name: Configure 3scale Service + hosts: localhost + connection: local + gather_facts: false + run_once: true + vars_files: + - group_vars/services.yml + - group_vars/3scale.yml + tasks: + - set_fact: + namespace: "{{ threescale_namespace }}" + config_deployment_name: "{{ threescale_config_deployment }}" + config_deployment_namespace: "{{ project_name }}" + resources_dir: "{{ resources_base_dir }}/3scale" + work_dir_name: 3scale + - include_role: + name: ../roles/3scale + when: > + ACTION is not defined or + ACTION is none or + ACTION|trim() == "" or + ACTION|trim() == "install" + - include_role: + name: ../roles/3scale + tasks_from: uninstall + when: > + ACTION is defined and + ACTION|trim() == "uninstall" diff --git a/ansible/playbooks/group_vars/3scale.yml b/ansible/playbooks/group_vars/3scale.yml new file mode 100644 index 00000000..91629332 --- /dev/null +++ b/ansible/playbooks/group_vars/3scale.yml @@ -0,0 +1,10 @@ +--- +threescale_enable: true +threescale_namespace: 3scale + +threescale_apicast_staging_svc: apicast-staging +threescale_apicast_prod_svc: apicast-production + +threescale_apicast_token: '12345' + +threescale_config_deployment: emergency-console diff --git a/ansible/playbooks/install.yml b/ansible/playbooks/install.yml index 1f687253..024aeeda 100644 --- a/ansible/playbooks/install.yml +++ b/ansible/playbooks/install.yml @@ -13,6 +13,7 @@ - group_vars/postgresql.yml - group_vars/sso.yml - group_vars/monitoring.yml + - group_vars/3scale.yml tasks: - include_role: diff --git a/ansible/resources/3scale/policy-config.json b/ansible/resources/3scale/policy-config.json new file mode 100644 index 00000000..c9cd42b2 --- /dev/null +++ b/ansible/resources/3scale/policy-config.json @@ -0,0 +1,25 @@ +[ + { + "name": "cors", + "version": "builtin", + "configuration": { + "allow_headers": [ + "Authorization" + ], + "allow_credentials": true, + "allow_methods": [ + "GET", + "OPTIONS", + "POST" + ], + "allow_origin": "*" + }, + "enabled": true + }, + { + "name": "apicast", + "version": "builtin", + "configuration": {}, + "enabled": true + } +] diff --git a/ansible/resources/3scale/route.yml b/ansible/resources/3scale/route.yml new file mode 100644 index 00000000..aa0de282 --- /dev/null +++ b/ansible/resources/3scale/route.yml @@ -0,0 +1,14 @@ +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: {{ name }} +spec: + port: + targetPort: gateway + tls: + termination: edge + to: + kind: Service + name: {{ apicast_service }} + weight: 100 + wildcardPolicy: None diff --git a/ansible/roles/3scale/defaults/main.yml b/ansible/roles/3scale/defaults/main.yml new file mode 100644 index 00000000..0b57cb20 --- /dev/null +++ b/ansible/roles/3scale/defaults/main.yml @@ -0,0 +1,6 @@ +--- +threescale_namespace: 3scale +threescale_admin_route: system-provider-admin +threescale_admin_secret: system-seed + +emergency_response_namespace: emergency-response-demo diff --git a/ansible/roles/3scale/meta/main.yml b/ansible/roles/3scale/meta/main.yml new file mode 100644 index 00000000..268e4869 --- /dev/null +++ b/ansible/roles/3scale/meta/main.yml @@ -0,0 +1,4 @@ +--- + +dependencies: + - role: work_dir diff --git a/ansible/roles/3scale/tasks/create-service.yml b/ansible/roles/3scale/tasks/create-service.yml new file mode 100644 index 00000000..8415ed22 --- /dev/null +++ b/ansible/roles/3scale/tasks/create-service.yml @@ -0,0 +1,168 @@ +--- +- name: Copy staging route template + template: + src: "{{ resources_dir }}/route.yml" + dest: "{{ work_dir }}/route.yml" + vars: + name: "{{ service_name }}-staging" + apicast_service: "{{ threescale_apicast_staging_svc }}" + +- name: Create staging route + oc_obj: + state: present + oc_binary: "{{ openshift_cli }}" + name: "{{ service_name }}-staging" + kind: route + namespace: "{{ namespace }}" + files: + - "{{ work_dir }}/route.yml" + +- name: Get staging route + shell: oc get route {{ service_name }}-staging -n {{ namespace }} -o jsonpath='{.spec.host}' + register: staging_route_result + +- set_fact: + staging_route: "https://{{ staging_route_result.stdout }}" + +- name: Copy production route template + template: + src: "{{ resources_dir }}/route.yml" + dest: "{{ work_dir }}/route.yml" + vars: + name: "{{ service_name }}-production" + apicast_service: "{{ threescale_apicast_prod_svc }}" + +- name: Create production route + oc_obj: + state: present + oc_binary: "{{ openshift_cli }}" + name: "{{ service_name }}-production" + kind: route + namespace: "{{ namespace }}" + files: + - "{{ work_dir }}/route.yml" + +- name: Get production route + shell: oc get route {{ service_name }}-production -n {{ namespace }} -o jsonpath='{.spec.host}' + register: production_route_result + +- set_fact: + production_route: "https://{{ production_route_result.stdout }}" + +- name: Create service + uri: + url: "{{ admin_route }}/admin/api/services.xml" + method: POST + return_content: yes + headers: + Content-Type: "application/x-www-form-urlencoded" + body: "access_token={{ admin_token }}&name={{ service_name | urlencode }}&deployment_option=hosted&backend_version={{ '1' if backend_version == 'oidc' else backend_version }}&system_name={{ service_name }}" + validate_certs: no + status_code: [201, 422] + register: create_svc_result + +- name: Get all services + uri: + url: "{{ admin_route }}/admin/api/services.xml?access_token={{ admin_token }}" + method: GET + return_content: yes + validate_certs: no + status_code: 200 + register: list_svc_result + +- name: Get service Id + xml: + xmlstring: '{{ list_svc_result.content }}' + xpath: //services//service//system_name[.='{{ service_name }}']/parent::service/id + content: text + register: xmlstring + +- debug: var=xmlstring.matches[0].id + +- set_fact: id={{ xmlstring.matches[0].id }} + +- name: Config backend service proxy + uri: + url: "{{ admin_route }}/admin/api/services/{{ id }}/proxy.xml" + method: PATCH + return_content: yes + headers: + Content-Type: "application/x-www-form-urlencoded" + body: "access_token={{ admin_token }}&endpoint={{ production_route | urlencode }}&credentials_location=headers\ + &sandbox_endpoint={{ staging_route | urlencode }}\ + &api_backend={{ backend_endpoint | urlencode }}" + validate_certs: no + +- name: Create application plan + uri: + url: "{{ admin_route }}/admin/api/services/{{ id }}/application_plans.xml" + method: POST + return_content: yes + headers: + Content-Type: "application/x-www-form-urlencoded" + body: "access_token={{ admin_token }}&name={{ display_name | urlencode }}&system_name={{ service_name }}&state=published" + validate_certs: no + status_code: [201, 422] + register: create_plan_result + +- name: Get all application plans + uri: + url: "{{ admin_route }}/admin/api/services/{{ id }}/application_plans.xml?access_token={{ admin_token }}" + method: GET + return_content: yes + validate_certs: no + status_code: 200 + register: list_app_plans_result + +- name: Get plan Id + xml: + xmlstring: '{{ list_app_plans_result.content }}' + xpath: //plans//plan//service_id[.='{{ id }}']/parent::plan/id + content: text + register: xmlstring + +- debug: var=xmlstring.matches[0].id + +- set_fact: plan_id={{ xmlstring.matches[0].id }} + +- set_fact: redirect_uri={{ ( app_config.redirect_uri is defined ) | ternary('&redirect_url=' + ( app_config.redirect_uri | default('') | urlencode ), '') }} + when: app_config is defined + +- debug: var=redirect_uri + +- name: Create application + uri: + url: "{{ admin_route }}/admin/api/accounts/{{ account_id }}/applications.xml" + method: POST + return_content: yes + headers: + Content-Type: "application/x-www-form-urlencoded" + body: "access_token={{ admin_token }}&plan_id={{ plan_id }}&name={{ service_name }}\ + &description={{ display_name }}&application_id={{ service_name }}\ + &user_key=12345{{ redirect_uri }}" + validate_certs: no + status_code: [201, 422] + register: create_app_result + when: app_config is defined + +- name: Get policy chain template + shell: 'cat {{ resources_dir }}/policy-config.json' + register: get_policies + +- name: Enable CORS + uri: + url: "{{ admin_route }}/admin/api/services/{{ id }}/proxy/policies.json" + method: PUT + return_content: yes + headers: + Content-Type: "application/x-www-form-urlencoded" + body: "access_token={{ admin_token }}&policies_config={{ get_policies.stdout | urlencode }}" + validate_certs: no + status_code: 200 + register: update_policies_result + +- set_fact: + config_key: "APICAST_{{ service_name | replace('-', '_') | upper }}" + +- name: Set config + shell: oc set env dc/{{ config_deployment_name }} -n {{ config_deployment_namespace }} {{ config_key }}={{ production_route }} diff --git a/ansible/roles/3scale/tasks/main.yml b/ansible/roles/3scale/tasks/main.yml new file mode 100644 index 00000000..e514ff60 --- /dev/null +++ b/ansible/roles/3scale/tasks/main.yml @@ -0,0 +1,61 @@ +--- +- name: Get 3scale admin token + shell: oc get secret {{ threescale_admin_secret }} -n {{ threescale_namespace }} -o jsonpath='{.data.ADMIN_ACCESS_TOKEN}' | base64 --decode + register: admin_token_cmd + +- name: Get 3scale admin route + shell: oc get route {{ threescale_admin_route }} -n {{ threescale_namespace }} -o jsonpath="{.spec.host}" + register: admin_route_cmd + +- set_fact: + threescale_admin_route: 'https://{{ admin_route_cmd.stdout }}' + threescale_admin_token: "{{ admin_token_cmd.stdout }}" + ocp_apps_domain: "{{ admin_route_cmd.stdout | replace('3scale-admin.', '') }}" + +- name: Create responder simulator 3scale service + include_tasks: ./create-service.yml + vars: + admin_route: '{{ threescale_admin_route }}' + admin_token: '{{ threescale_admin_token }}' + apicast_token: '{{ threescale_apicast_token }}' + account_id: '3' + service_name: responder-simulator-5 + backend_version: '1' + backend_endpoint: http://responder-simulator.{{ emergency_response_namespace }}.svc:8080 + +- name: Create responder service 3scale service + include_tasks: ./create-service.yml + vars: + admin_route: '{{ threescale_admin_route }}' + admin_token: '{{ threescale_admin_token }}' + apicast_token: '{{ threescale_apicast_token }}' + account_id: '3' + service_name: responder-service-5 + backend_version: '1' + backend_endpoint: http://responder-service.{{ emergency_response_namespace }}.svc:8080 + +- name: Create incident service 3scale service + include_tasks: ./create-service.yml + vars: + admin_route: '{{ threescale_admin_route }}' + admin_token: '{{ threescale_admin_token }}' + apicast_token: '{{ threescale_apicast_token }}' + account_id: '3' + service_name: incident-service-5 + backend_version: '1' + backend_endpoint: http://incident-service.{{ emergency_response_namespace }}.svc:8080 + +- name: Create mission service 3scale service + include_tasks: ./create-service.yml + vars: + admin_route: '{{ threescale_admin_route }}' + admin_token: '{{ threescale_admin_token }}' + apicast_token: '{{ threescale_apicast_token }}' + account_id: '3' + display_name: Mission Service + service_name: mission-service-5 + backend_version: '1' + backend_endpoint: http://mission-service.{{ emergency_response_namespace }}.svc:8080 + +- name: Set config + shell: oc set env dc/{{ config_deployment_name }} -n {{ config_deployment_namespace }} APICAST_ENABLED=true APICAST_TOKEN={{ threescale_apicast_token }} diff --git a/ansible/roles/openshift_install/tasks/main.yml b/ansible/roles/openshift_install/tasks/main.yml index a4bef4ff..5114d941 100644 --- a/ansible/roles/openshift_install/tasks/main.yml +++ b/ansible/roles/openshift_install/tasks/main.yml @@ -305,3 +305,14 @@ monitor_namespace: "{{ namespace_services }}" resources_dir: "{{ resources_base_dir }}/monitoring" work_dir_name: monitoring + +- name: setup 3scale with demo services + import_role: + name: 3scale + vars: + namespace: "{{ threescale_namespace }}" + config_deployment_name: "{{ threescale_config_deployment }}" + config_deployment_namespace: "{{ project_name }}" + resources_dir: "{{ resources_base_dir }}/3scale" + work_dir_name: 3scale + when: threescale_enable | default(true) | bool