From 61827ccfbd3d5a984c6820f4f2cc5b9a7dcfc776 Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Tue, 29 Sep 2015 21:49:24 -0500 Subject: [PATCH] Implement horizon venv support This commit conditionally allows the os_horizon role to install build and deploy within a venv. This is the new default behavior of the role however the functionality can be disabled. Change-Id: I136eed8bd40f4ae5bc77f3fa925e4cbc6f842271 Implements: blueprint enable-venv-support-within-the-roles Signed-off-by: Kevin Carter --- defaults/main.yml | 25 ++++++- tasks/horizon_db_setup.yml | 6 +- tasks/horizon_install.yml | 21 +++++- tasks/horizon_post_install.yml | 50 +++++++++---- tasks/horizon_pre_install.yml | 74 ++++++++++++++++++- .../horizon-manage.py.j2 | 8 ++ templates/horizon_django.wsgi.j2 | 22 ++++++ templates/openstack_dashboard.conf.j2 | 7 +- 8 files changed, 184 insertions(+), 29 deletions(-) rename files/horizon-manage.py => templates/horizon-manage.py.j2 (81%) create mode 100644 templates/horizon_django.wsgi.j2 diff --git a/defaults/main.yml b/defaults/main.yml index 5b4ead93..f628c436 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -13,13 +13,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Defines that the role will be deployed on a host machine -is_metal: true - ## Verbosity Options debug: False verbose: True +# Name of the virtual env to deploy into +horizon_venv_tag: untagged +horizon_venv_bin: "/openstack/venvs/horizon-{{ horizon_venv_tag }}/bin" + +# Set this to enable or disable installing in a venv +horizon_venv_enabled: true + +# The bin path defaults to the venv path however if installation in a +# venv is disabled the bin path will be dynamically set based on the +# system path used when the installing. +horizon_bin: "{{ horizon_venv_bin }}" + ## System info horizon_system_user_name: horizon horizon_system_group_name: www-data @@ -44,7 +53,10 @@ horizon_session_timeout: 1800 horizon_help_url: http://docs.openstack.org ## Installation directories -horizon_lib_dir: /usr/local/lib/python2.7/dist-packages +horizon_venv_lib_dir: "{{ horizon_bin | dirname }}/lib/python2.7/dist-packages" +horizon_non_venv_lib_dir: "/usr/local/lib/python2.7/dist-packages" +horizon_lib_dir: "{{ (horizon_venv_enabled | bool) | ternary(horizon_venv_lib_dir, horizon_non_venv_lib_dir) }}" +horizon_lib_wsgi_file: "{{ horizon_lib_dir }}/openstack_dashboard/wsgi/django.wsgi" horizon_endpoint_type: internalURL @@ -115,6 +127,11 @@ horizon_apt_packages: - libxslt1.1 - openssl +# horizon packages that must be installed before anything else +horizon_requires_pip_packages: + - virtualenv + - python-keystoneclient # Keystoneclient needed to OSA keystone lib + horizon_pip_packages: - django-appconf - greenlet diff --git a/tasks/horizon_db_setup.yml b/tasks/horizon_db_setup.yml index 675991a1..74562d1d 100644 --- a/tasks/horizon_db_setup.yml +++ b/tasks/horizon_db_setup.yml @@ -40,19 +40,21 @@ - horizon-db-setup - name: Perform a horizon DB sync - command: horizon-manage.py syncdb --noinput + command: "{{ horizon_bin }}/horizon-manage.py syncdb --noinput" sudo: yes sudo_user: "{{ horizon_system_user_name }}" tags: + - horizon-db-setup - horizon-db-sync - horizon-setup + - horizon-command-bin - name: Register DB session cleanup cron cron: name: "Clear out expired sessions" minute: "{{ 58 | random(start=2) }}" hour: 21 - job: "/usr/local/bin/horizon-manage.py clearsessions" + job: "{{ horizon_bin }}/horizon-manage.py clearsessions" user: "{{ horizon_system_user_name }}" state: present tags: diff --git a/tasks/horizon_install.yml b/tasks/horizon_install.yml index 674a0cb2..beb6a70b 100644 --- a/tasks/horizon_install.yml +++ b/tasks/horizon_install.yml @@ -37,7 +37,24 @@ - horizon-install - horizon-apt-packages -- name: Install pip packages +- name: Install pip packages (venv) + pip: + name: "{{ item }}" + state: present + virtualenv: "{{ horizon_venv_bin | dirname }}" + virtualenv_site_packages: "no" + extra_args: "{{ pip_install_options|default('') }}" + register: install_packages + until: install_packages|success + retries: 5 + delay: 2 + with_items: + - "{{ horizon_pip_packages }}" + when: horizon_venv_enabled | bool + tags: + - horizon-pip-packages + +- name: Install pip packages (no venv) pip: name: "{{ item }}" state: present @@ -48,6 +65,6 @@ delay: 2 with_items: - "{{ horizon_pip_packages }}" + when: not horizon_venv_enabled | bool tags: - - horizon-install - horizon-pip-packages diff --git a/tasks/horizon_post_install.yml b/tasks/horizon_post_install.yml index 4dd5cacd..ea82206d 100644 --- a/tasks/horizon_post_install.yml +++ b/tasks/horizon_post_install.yml @@ -13,6 +13,25 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Because there is no specific "horizon" command this method +# is looking for the "keystone" command to set the horizon +# command path. +- name: Get horizon command path + command: which keystone + register: horizon_command_path + when: + - not horizon_venv_enabled | bool + tags: + - horizon-command-bin + +- name: Set horizon command path + set_fact: + horizon_bin: "{{ horizon_command_path.stdout | dirname }}" + when: + - not horizon_venv_enabled | bool + tags: + - horizon-command-bin + - name: Setup Horizon config(s) template: src: "{{ item.src }}" @@ -22,22 +41,11 @@ mode: "{{ item.mode }}" with_items: - { src: "horizon_local_settings.py.j2", dest: "/etc/horizon/local_settings.py", mode: "0644" } + - { src: "horizon-manage.py.j2", dest: "{{ horizon_bin }}/horizon-manage.py", mode: "0755" } notify: Restart apache2 tags: - horizon-configs -- name: Setup Horizon config(s) - copy: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - owner: "{{ horizon_system_user_name }}" - group: "{{ horizon_system_group_name }}" - mode: "{{ item.mode }}" - with_items: - - { src: "horizon-manage.py", dest: "/usr/local/bin/horizon-manage.py", mode: "0755" } - tags: - - horizon-configs - - name: Create horizon links file: src: "{{ item.src }}" @@ -55,8 +63,22 @@ sudo: yes sudo_user: "{{ horizon_system_user_name }}" with_items: - - horizon-manage.py collectstatic --noinput - - horizon-manage.py compress --force + - "{{ horizon_bin }}/horizon-manage.py collectstatic --noinput" + - "{{ horizon_bin }}/horizon-manage.py compress --force" tags: - horizon-configs - horizon-static-collect + - horizon-command-bin + +- name: Setup Horizon config(s) + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ horizon_system_user_name }}" + group: "{{ horizon_system_group_name }}" + with_items: + - { src: "horizon_django.wsgi.j2", dest: "{{ horizon_lib_wsgi_file }}" } + notify: Restart apache2 + tags: + - horizon-configs + - horizon-wsgi-venv diff --git a/tasks/horizon_pre_install.yml b/tasks/horizon_pre_install.yml index f06d01ec..60053d01 100644 --- a/tasks/horizon_pre_install.yml +++ b/tasks/horizon_pre_install.yml @@ -34,16 +34,82 @@ - horizon-user - name: Create horizon dir + file: + path: "{{ item.path }}" + state: "directory" + owner: "{{ item.owner|default(horizon_system_user_name) }}" + group: "{{ item.group|default(horizon_system_group_name) }}" + with_items: + - { path: "/openstack", mode: "0755", owner: "root", group: "root" } + - { path: "/etc/horizon", mode: "2755" } + - { path: "{{ horizon_system_user_home }}", mode: "2755" } + tags: + - horizon-dirs + +- name: Create horizon venv dir file: path: "{{ item.path }}" state: directory owner: "{{ item.owner|default(horizon_system_user_name) }}" group: "{{ item.group|default(horizon_system_group_name) }}" with_items: - - { path: "/etc/horizon" } - - { path: "{{ horizon_system_user_home }}" } - - { path: "/usr/local/lib/python2.7/dist-packages/static" } - - { path: "/usr/local/lib/python2.7/dist-packages/openstack_dashboard/local" } + - { path: "/openstack/venvs", mode: "0755", owner: "root", group: "root" } + - { path: "{{ horizon_venv_bin }}" } + when: horizon_venv_enabled | bool + tags: + - horizon-dirs + +- name: Install requires pip packages + pip: + name: "{{ item }}" + state: present + extra_args: "{{ pip_install_options|default('') }}" + register: install_packages + until: install_packages|success + retries: 5 + delay: 2 + with_items: + - "{{ horizon_requires_pip_packages }}" + tags: + - horizon-pip-packages + +- name: Create horizon venv + pip: + name: "{{ item }}" + state: present + virtualenv: "{{ horizon_venv_bin | dirname }}" + virtualenv_site_packages: "no" + extra_args: "{{ pip_install_options|default('') }}" + with_items: + - "{{ horizon_requires_pip_packages }}" + when: horizon_venv_enabled | bool + tags: + - horizon-pip-packages + +- name: Create horizon links for venv + file: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ horizon_system_user_name }}" + group: "{{ horizon_system_group_name }}" + state: "link" + with_items: + - src: "{{ horizon_lib_dir | dirname }}/site-packages" + dest: "{{ horizon_lib_dir }}" + when: horizon_venv_enabled | bool + tags: + - horizon-configs + +- name: Create static horizon dir + file: + path: "{{ item.path }}" + state: "directory" + owner: "{{ item.owner|default(horizon_system_user_name) }}" + group: "{{ item.group|default(horizon_system_group_name) }}" + with_items: + - { path: "{{ horizon_lib_dir }}/static", mode: "2755" } + - { path: "{{ horizon_lib_dir }}/openstack_dashboard", mode: "2755" } + - { path: "{{ horizon_lib_dir }}/openstack_dashboard/local", mode: "2755" } tags: - horizon-dirs diff --git a/files/horizon-manage.py b/templates/horizon-manage.py.j2 similarity index 81% rename from files/horizon-manage.py rename to templates/horizon-manage.py.j2 index 5818a6de..b0fd422b 100644 --- a/files/horizon-manage.py +++ b/templates/horizon-manage.py.j2 @@ -13,6 +13,14 @@ # under the License. import os + +{% if horizon_venv_enabled | bool %} + +activate_this = os.path.expanduser("{{ horizon_venv_bin }}/activate_this.py") +execfile(activate_this, dict(__file__=activate_this)) + +{% endif %} + import sys from django.core.management import execute_from_command_line # noqa diff --git a/templates/horizon_django.wsgi.j2 b/templates/horizon_django.wsgi.j2 new file mode 100644 index 00000000..60edb1e5 --- /dev/null +++ b/templates/horizon_django.wsgi.j2 @@ -0,0 +1,22 @@ +import logging +import os + +{% if horizon_venv_enabled | bool %} + +activate_this = os.path.expanduser("{{ horizon_venv_bin }}/activate_this.py") +execfile(activate_this, dict(__file__=activate_this)) + +{% endif %} + +import sys +from django.core.wsgi import get_wsgi_application +from django.conf import settings + +# Add this file path to sys.path in order to import settings +sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) +os.environ['DJANGO_SETTINGS_MODULE'] = 'openstack_dashboard.settings' +sys.stdout = sys.stderr + +DEBUG = False + +application = get_wsgi_application() \ No newline at end of file diff --git a/templates/openstack_dashboard.conf.j2 b/templates/openstack_dashboard.conf.j2 index f8d8f962..ed77df24 100644 --- a/templates/openstack_dashboard.conf.j2 +++ b/templates/openstack_dashboard.conf.j2 @@ -29,13 +29,12 @@ SSLCipherSuite {{ horizon_ssl_cipher_suite }} SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown - WSGIScriptAlias / {{ horizon_lib_dir }}/openstack_dashboard/wsgi/django.wsgi + WSGIScriptAlias / {{ horizon_lib_wsgi_file }} WSGIDaemonProcess horizon user={{ horizon_system_user_name }} group={{ horizon_system_group_name }} processes={{ ansible_processor_cores }} threads={{ threads if threads > 0 else 1 }} WSGIProcessGroup horizon WSGIApplicationGroup horizon - Alias /static {{ horizon_lib_dir }}/static/ - + Order allow,deny allow from all @@ -43,6 +42,8 @@ + Alias /static {{ horizon_lib_dir }}/static/ + Options -FollowSymlinks AllowOverride None