Add theme settings for Horizon Mitaka and newer

Issue: PROD-20920

Change-Id: I8b2c8a0f7f3f1218bf7d85a12da198628c53db0a
diff --git a/README.rst b/README.rst
index 71fa431..6d6a085 100644
--- a/README.rst
+++ b/README.rst
@@ -390,6 +390,46 @@
             mail:
               host: '127.0.0.1'
 
+Set advanced theme options (for Horizon version Mitaka and newer).
+
+Full example:
+
+.. code-block:: yaml
+
+  horizon:
+    server:
+      themes:
+        default: default                           # optional, default: "default"
+        directory: themes                          # optional, default: "themes"
+        cookie_name: theme                         # optional, default: "theme"
+        available:
+          default:                                 # slug
+            name: "Default"                        # display name
+            description: "Default style theme"
+            path: "themes/default"                 # optional, default: "<directory>/<slug>", e.g. "themes/default"
+            enabled: True
+          material:
+            name: "Material"
+            description: "Google's Material Design style theme"
+            path: "themes/material"
+            enabled: True
+
+Minimal example:
+
+.. code-block:: yaml
+
+  horizon:
+    server:
+      theme:
+        available:
+          default:                                 # slug
+            name: "Default"                        # display name
+            description: "Default style theme"
+          material:
+            name: "Material"
+            description: "Google's Material Design style theme"
+
+
 API versions override
 
 .. code-block:: yaml
diff --git a/horizon/files/local_settings/mitaka_settings.py b/horizon/files/local_settings/mitaka_settings.py
index be188b5..d161c42 100644
--- a/horizon/files/local_settings/mitaka_settings.py
+++ b/horizon/files/local_settings/mitaka_settings.py
@@ -1,4 +1,6 @@
 import os
+
+from django.utils.translation import pgettext_lazy
 from django.utils.translation import ugettext_lazy as _
 from openstack_dashboard import exceptions
 
@@ -29,16 +31,29 @@
     'disable_password_reveal': True,
     'password_autocomplete': 'off'
 }
-{%- if app.theme is defined or (app.plugin is defined and app.plugin.horizon_theme is defined) %}
-{%- if app.theme is defined %}
-CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
-{%- elif app.plugin.horizon_theme.theme_name is defined %}
-# Enable custom theme if it is present.
-try:
-  from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
-except ImportError:
-  pass
-{%- endif %}
+{%- if app.themes is defined %}
+# 'key', 'label', 'path'
+{%- set theme_dir = app.themes.get('directory', 'themes') %}
+AVAILABLE_THEMES = [
+{%- for slug, theme in app.themes.get('available', {}).iteritems() %}
+  {%- if theme.get('enabled', True) %}
+    (
+        "{{ slug }}",
+        pgettext_lazy("{{ theme.description }}", "{{ theme.name }}"),
+        "{{ theme.get('path', theme_dir + '/' + slug ) }}"
+    ),
+  {%- endif %}
+{%- endfor %}
+]
+
+# The default theme if no cookie is present
+DEFAULT_THEME = '{{ app.themes.get("default", "default") }}'
+
+# Theme Static Directory
+THEME_COLLECTION_DIR = '{{ theme_dir }}'
+
+# Theme Cookie Name
+THEME_COOKIE_NAME = '{{ app.themes.get("cookie_name", "theme") }}'
 {%- endif %}
 
 INSTALLED_APPS = (
diff --git a/horizon/files/local_settings/newton_settings.py b/horizon/files/local_settings/newton_settings.py
index be188b5..d161c42 100644
--- a/horizon/files/local_settings/newton_settings.py
+++ b/horizon/files/local_settings/newton_settings.py
@@ -1,4 +1,6 @@
 import os
+
+from django.utils.translation import pgettext_lazy
 from django.utils.translation import ugettext_lazy as _
 from openstack_dashboard import exceptions
 
@@ -29,16 +31,29 @@
     'disable_password_reveal': True,
     'password_autocomplete': 'off'
 }
-{%- if app.theme is defined or (app.plugin is defined and app.plugin.horizon_theme is defined) %}
-{%- if app.theme is defined %}
-CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
-{%- elif app.plugin.horizon_theme.theme_name is defined %}
-# Enable custom theme if it is present.
-try:
-  from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
-except ImportError:
-  pass
-{%- endif %}
+{%- if app.themes is defined %}
+# 'key', 'label', 'path'
+{%- set theme_dir = app.themes.get('directory', 'themes') %}
+AVAILABLE_THEMES = [
+{%- for slug, theme in app.themes.get('available', {}).iteritems() %}
+  {%- if theme.get('enabled', True) %}
+    (
+        "{{ slug }}",
+        pgettext_lazy("{{ theme.description }}", "{{ theme.name }}"),
+        "{{ theme.get('path', theme_dir + '/' + slug ) }}"
+    ),
+  {%- endif %}
+{%- endfor %}
+]
+
+# The default theme if no cookie is present
+DEFAULT_THEME = '{{ app.themes.get("default", "default") }}'
+
+# Theme Static Directory
+THEME_COLLECTION_DIR = '{{ theme_dir }}'
+
+# Theme Cookie Name
+THEME_COOKIE_NAME = '{{ app.themes.get("cookie_name", "theme") }}'
 {%- endif %}
 
 INSTALLED_APPS = (
diff --git a/horizon/files/local_settings/ocata_settings.py b/horizon/files/local_settings/ocata_settings.py
index be188b5..aebbc5e 100644
--- a/horizon/files/local_settings/ocata_settings.py
+++ b/horizon/files/local_settings/ocata_settings.py
@@ -1,4 +1,6 @@
 import os
+
+from django.utils.translation import pgettext_lazy
 from django.utils.translation import ugettext_lazy as _
 from openstack_dashboard import exceptions
 
@@ -29,16 +31,30 @@
     'disable_password_reveal': True,
     'password_autocomplete': 'off'
 }
-{%- if app.theme is defined or (app.plugin is defined and app.plugin.horizon_theme is defined) %}
-{%- if app.theme is defined %}
-CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
-{%- elif app.plugin.horizon_theme.theme_name is defined %}
-# Enable custom theme if it is present.
-try:
-  from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
-except ImportError:
-  pass
-{%- endif %}
+
+{%- if app.themes is defined %}
+# 'key', 'label', 'path'
+{%- set theme_dir = app.themes.get('directory', 'themes') %}
+AVAILABLE_THEMES = [
+{%- for slug, theme in app.themes.get('available', {}).iteritems() %}
+  {%- if theme.get('enabled', True) %}
+    (
+        "{{ slug }}",
+        pgettext_lazy("{{ theme.description }}", "{{ theme.name }}"),
+        "{{ theme.get('path', theme_dir + '/' + slug ) }}"
+    ),
+  {%- endif %}
+{%- endfor %}
+]
+
+# The default theme if no cookie is present
+DEFAULT_THEME = '{{ app.themes.get("default", "default") }}'
+
+# Theme Static Directory
+THEME_COLLECTION_DIR = '{{ theme_dir }}'
+
+# Theme Cookie Name
+THEME_COOKIE_NAME = '{{ app.themes.get("cookie_name", "theme") }}'
 {%- endif %}
 
 INSTALLED_APPS = (
diff --git a/horizon/files/local_settings/queens_settings.py b/horizon/files/local_settings/queens_settings.py
index be188b5..d161c42 100644
--- a/horizon/files/local_settings/queens_settings.py
+++ b/horizon/files/local_settings/queens_settings.py
@@ -1,4 +1,6 @@
 import os
+
+from django.utils.translation import pgettext_lazy
 from django.utils.translation import ugettext_lazy as _
 from openstack_dashboard import exceptions
 
@@ -29,16 +31,29 @@
     'disable_password_reveal': True,
     'password_autocomplete': 'off'
 }
-{%- if app.theme is defined or (app.plugin is defined and app.plugin.horizon_theme is defined) %}
-{%- if app.theme is defined %}
-CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
-{%- elif app.plugin.horizon_theme.theme_name is defined %}
-# Enable custom theme if it is present.
-try:
-  from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
-except ImportError:
-  pass
-{%- endif %}
+{%- if app.themes is defined %}
+# 'key', 'label', 'path'
+{%- set theme_dir = app.themes.get('directory', 'themes') %}
+AVAILABLE_THEMES = [
+{%- for slug, theme in app.themes.get('available', {}).iteritems() %}
+  {%- if theme.get('enabled', True) %}
+    (
+        "{{ slug }}",
+        pgettext_lazy("{{ theme.description }}", "{{ theme.name }}"),
+        "{{ theme.get('path', theme_dir + '/' + slug ) }}"
+    ),
+  {%- endif %}
+{%- endfor %}
+]
+
+# The default theme if no cookie is present
+DEFAULT_THEME = '{{ app.themes.get("default", "default") }}'
+
+# Theme Static Directory
+THEME_COLLECTION_DIR = '{{ theme_dir }}'
+
+# Theme Cookie Name
+THEME_COOKIE_NAME = '{{ app.themes.get("cookie_name", "theme") }}'
 {%- endif %}
 
 INSTALLED_APPS = (
diff --git a/metadata/service/server/cluster.yml b/metadata/service/server/cluster.yml
index cb27011..1600163 100644
--- a/metadata/service/server/cluster.yml
+++ b/metadata/service/server/cluster.yml
@@ -42,6 +42,19 @@
         host: ${_param:horizon_identity_host}
         encryption: ${_param:horizon_identity_encryption}
         endpoint_type: ${_param:horizon_identity_endpoint_type}
+      themes:
+        default: "default"
+        directory: "themes"
+        cookie_name: "theme"
+        available:
+          default:
+            name: "Default"
+            description: "Default style theme"
+            enabled: True
+          material:
+            name: "Material"
+            description: "Google's Material Design style theme"
+            enabled: True
       policy:
         identity:
           source: file
diff --git a/metadata/service/server/single.yml b/metadata/service/server/single.yml
index 0325076..a191165 100644
--- a/metadata/service/server/single.yml
+++ b/metadata/service/server/single.yml
@@ -40,6 +40,19 @@
         host: ${_param:horizon_identity_host}
         encryption: ${_param:horizon_identity_encryption}
         endpoint_type: ${_param:horizon_identity_endpoint_type}
+      themes:
+        default: "default"
+        directory: "themes"
+        cookie_name: "theme"
+        available:
+          default:
+            name: "Default"
+            description: "Default style theme"
+            enabled: True
+          material:
+            name: "Material"
+            description: "Google's Material Design style theme"
+            enabled: True
       policy:
         identity:
           source: file
diff --git a/tests/pillar/cluster.sls b/tests/pillar/cluster.sls
index 3e43ab8..4b7f1d0 100644
--- a/tests/pillar/cluster.sls
+++ b/tests/pillar/cluster.sls
@@ -51,6 +51,19 @@
       password_autocomplete: off
     openstack_neutron_network:
       enable_fip_topology_check: False
+    themes:
+      default: default  
+      directory: themes  
+      cookie_name: theme  
+      available:
+        default:
+          name: "Default"
+          description: "Default style theme"
+          path: "themes/default"                 
+        material:
+          name: "Material"
+          description: "Google's Material Design style theme"
+          path: "themes/material"
 
 haproxy:
   proxy:
diff --git a/tests/pillar/single.sls b/tests/pillar/single.sls
index a364e2e..08f6794 100644
--- a/tests/pillar/single.sls
+++ b/tests/pillar/single.sls
@@ -55,3 +55,16 @@
       enable_fip_topology_check: False
     default_domain: default
     multidomain: False
+    themes:
+      default: default
+      directory: themes
+      cookie_name: theme
+      available:
+        default:
+          name: "Default"
+          description: "Default style theme"
+          path: "themes/default"
+        material:
+          name: "Material"
+          description: "Google's Material Design style theme"
+          path: "themes/material"