From 0de33a024358d68a2e37bb2e84a86d42b03cc0de Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Thu, 1 Apr 2021 10:20:10 +0300 Subject: [PATCH] Use uWSGI for trove-api This migrate trove-api to usage of the uwsgi from native service to align with other service way of deployment and since that's how service is tested in devstack. Change-Id: I83ad3af282942ff9714757e863f393894ac35f45 --- defaults/main.yml | 14 +++++--- tasks/main.yml | 41 ++++++++++++----------- tasks/trove_post_install.yml | 15 +++++++++ templates/wsgi.py.j2 | 40 ++++++++++++++++++++++ tests/ansible-role-requirements.yml | 4 +++ vars/main.yml | 51 +++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 templates/wsgi.py.j2 create mode 100644 vars/main.yml diff --git a/defaults/main.yml b/defaults/main.yml index c75d67e..9937a50 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -67,6 +67,10 @@ trove_profiler_enabled: false trove_api_workers_max: 16 trove_api_workers: "{{ [[(ansible_facts['processor_vcpus']//ansible_facts['processor_threads_per_core'])|default(1), 1] | max * 2, trove_api_workers_max] | min }}" +# uWSGI settings +trove_wsgi_threads: 1 +trove_use_uwsgi: True + ## Cap the maximum number of threads / workers when a user value is unspecified. trove_conductor_workers_max: 16 trove_conductor_workers: "{{ [[(ansible_facts['processor_vcpus']//ansible_facts['processor_threads_per_core'])|default(1), 1] | max * 2, trove_conductor_workers_max] | min }}" @@ -235,8 +239,8 @@ trove_conductor_config_overrides: {} trove_taskmanager_config_overrides: {} trove_guestagent_config_overrides: {} trove_policy_overrides: {} - trove_api_init_config_overrides: {} +trove_api_uwsgi_ini_overrides: {} trove_conductor_init_config_overrides: {} trove_taskmanager_init_config_overrides: {} @@ -247,6 +251,11 @@ trove_services: service_name: trove-api execstarts: "{{ trove_bin }}/trove-api" init_config_overrides: "{{ trove_api_init_config_overrides }}" + wsgi_app: "{{ trove_use_uwsgi }}" + wsgi_name: trove-api-wsgi + uwsgi_overrides: "{{ trove_api_uwsgi_ini_overrides }}" + uwsgi_bind_address: "{{ trove_service_host }}" + uwsgi_port: "{{ trove_service_port }}" start_order: 1 trove-conductor: group: trove_conductor @@ -260,6 +269,3 @@ trove_services: execstarts: "{{ trove_bin }}/trove-taskmanager" init_config_overrides: "{{ trove_taskmanager_init_config_overrides }}" start_order: 3 - -_trove_is_first_play_host: "{{ (trove_services['trove-api']['group'] in group_names and inventory_hostname == (groups[trove_services['trove-api']['group']] | intersect(ansible_play_hosts)) | first) | bool }}" -_trove_conductor_is_first_play_host: "{{ (trove_services['trove-conductor']['group'] in group_names and inventory_hostname == (groups[trove_services['trove-conductor']['group']] | intersect(ansible_play_hosts)) | first) | bool }}" diff --git a/tasks/main.yml b/tasks/main.yml index c09250f..391d339 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -109,7 +109,7 @@ - trove-config - name: Run the systemd service role - import_role: + include_role: name: systemd_service vars: systemd_user_name: "{{ trove_system_user_name }}" @@ -121,28 +121,31 @@ systemd_BlockIOAccounting: true systemd_MemoryAccounting: true systemd_TasksAccounting: true - systemd_services: |- - {% set services = [] %} - {% for key, value in trove_services.items() %} - {% if (value['group'] in group_names) %} - {% set _ = value.update( - { - 'service_key': key, - 'enabled': 'yes', - 'state': 'started', - 'config_overrides': value.init_config_overrides - } - ) - %} - {% set _ = value.pop('init_config_overrides') -%} - {% set _ = services.append(value) %} - {% endif %} - {% endfor %} - {{ services }} + systemd_services: + - service_name: "{{ service_var.service_name }}" + enabled: yes + state: started + execstarts: "{{ service_var.execstarts }}" + execreloads: "{{ service_var.execreloads | default([]) }}" + config_overrides: "{{ service_var.init_config_overrides }}" + with_items: "{{ filtered_trove_services }}" + loop_control: + loop_var: service_var tags: - trove-config - systemd-service +- name: Import uwsgi role + import_role: + name: uwsgi + vars: + uwsgi_services: "{{ uwsgi_trove_services }}" + uwsgi_install_method: "source" + tags: + - trove-install + - trove-config + - uwsgi + - import_tasks: service_setup.yml vars: _project_name: "{{ trove_service_project_name }}" diff --git a/tasks/trove_post_install.yml b/tasks/trove_post_install.yml index 336f3ef..cce0d3b 100644 --- a/tasks/trove_post_install.yml +++ b/tasks/trove_post_install.yml @@ -35,6 +35,7 @@ config_type: "ini" notify: - Restart trove API services + - Restart uwsgi services when: inventory_hostname in groups['trove_api'] - name: Implement policy.yaml if there are overrides configured @@ -59,6 +60,20 @@ tags: - trove-policy-override +- name: Drop trove wsgi binary + template: + src: wsgi.py.j2 + dest: "{{ trove_bin }}/trove-api-wsgi" + owner: "{{ trove_system_user_name }}" + group: "{{ trove_system_group_name }}" + mode: "0755" + when: + - trove_use_uwsgi | bool + - inventory_hostname in groups['trove_api'] + notify: + - Restart trove API services + - Restart uwsgi services + - name: Drop trove-conductor Config(s) config_template: src: "{{ item.src }}" diff --git a/templates/wsgi.py.j2 b/templates/wsgi.py.j2 new file mode 100644 index 0000000..a3ff6d1 --- /dev/null +++ b/templates/wsgi.py.j2 @@ -0,0 +1,40 @@ +# Copyright 2021 City Network International AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Used for deploying Trove API through mod-wsgi +""" + +from oslo_log import log as logging +from trove.cmd.common import with_initialize +from trove.common import pastedeploy +from trove.common import profile + +LOG = logging.getLogger('trove.cmd.app') + + +@with_initialize +def wsgimain(CONF): + from trove.common import cfg + from trove.common import notification + from trove.instance import models as inst_models + + notification.DBaaSAPINotification.register_notify_callback( + inst_models.persist_instance_fault) + cfg.set_api_config_defaults() + profile.setup_profiler('api', CONF.host) + conf_file = CONF.find_file(CONF.api_paste_config) + LOG.debug("Trove started on %s", CONF.host) + return pastedeploy.paste_deploy_app(conf_file, 'trove', {}) + +application = wsgimain() diff --git a/tests/ansible-role-requirements.yml b/tests/ansible-role-requirements.yml index a9f1c7e..12f508a 100644 --- a/tests/ansible-role-requirements.yml +++ b/tests/ansible-role-requirements.yml @@ -55,3 +55,7 @@ src: https://opendev.org/openstack/ansible-role-python_venv_build scm: git version: master +- name: uwsgi + src: https://opendev.org/openstack/ansible-role-uwsgi + scm: git + version: master diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..05c485c --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,51 @@ +--- +# Copyright 2021 City Network International AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +_trove_is_first_play_host: "{{ (trove_services['trove-api']['group'] in group_names and inventory_hostname == (groups[trove_services['trove-api']['group']] | intersect(ansible_play_hosts)) | first) | bool }}" +_trove_conductor_is_first_play_host: "{{ (trove_services['trove-conductor']['group'] in group_names and inventory_hostname == (groups[trove_services['trove-conductor']['group']] | intersect(ansible_play_hosts)) | first) | bool }}" + +filtered_trove_services: |- + {% set services = [] %} + {% for key, value in trove_services.items() %} + {% if (value['group'] in group_names) and + (('condition' not in value) or + ('condition' in value and value['condition'])) and + not ('wsgi_app' in value and value['wsgi_app']) %} + {% set _ = value.update({'service_key': key}) %} + {% set _ = services.append(value) %} + {% endif %} + {% endfor %} + {{ services | sort(attribute='start_order') }} + +uwsgi_trove_services: |- + {% set services = {} %} + {% for key, value in trove_services.items() %} + {% if (value['group'] in group_names) and + (('condition' not in value) or ('condition' in value and value['condition'])) + and ('wsgi_app' in value and value['wsgi_app']) %} + {% set _ = value.update( + { + 'wsgi_path': trove_bin ~ '/' ~ value.wsgi_name, + 'wsgi_venv': trove_bin | dirname, + 'uwsgi_uid': trove_system_user_name, + 'uwsgi_guid': trove_system_group_name, + 'uwsgi_processes': trove_api_workers, + 'uwsgi_threads': trove_wsgi_threads, + } + ) %} + {% set _ = services.update({key: value}) %} + {% endif %} + {% endfor %} + {{ services }}