- name: Restart Samba
@@ -2146,7 +2343,7 @@ This section contains custom modules for the yaVDR Playbooks. They are used to c
Autor: Alexander Grothe
-
Created: 2017-03-17 Fr 11:41
+
Created: 2017-03-26 So 13:57
Validate
diff --git a/Manual.org b/Manual.org
index 0545ed2..680a14e 100644
--- a/Manual.org
+++ b/Manual.org
@@ -97,13 +97,8 @@ For a headless server installation ~yavdr07-headless.yml~ is a good choice
This playbook can either be used to run the installation on the localhost or any other PC in the network that can be accessed via ssh. Simply add the host names or IP addresses to the hosts file in the respective section:
#+BEGIN_SRC conf :tangle localhost_inventory :mkdirp yes
-[yavdr-full]
+[localhost]
localhost connection=local
-#192.168.1.116
-
-[yavdr-headless]
-
-[yavdr-client]
#+END_SRC
* Group Variables
@@ -615,6 +610,30 @@ systemctl --user import-environment
enabled: yes
state: started
#+END_SRC
+*** templates
+#+BEGIN_SRC conf :tangle roles/yavdr-xorg/templates/x-verbose.service.j2
+[Unit]
+Description=X with verbose logging on %I
+Wants=graphical.target
+Before=graphical.target
+
+[Service]
+Type=forking
+ExecStart=/usr/bin/x-daemon -logverbose 6 -noreset %I
+#+END_SRC
+** display-data
+*** tasks
+#+BEGIN_SRC yaml :tangle roles/display-data/tasks/main.yml
+---
+# file: roles/display-data/tasks/main.yml
+
+- name: "detect xorg configuration"
+ action: xorg_facts
+
+- debug:
+ var: xorg
+ verbosity: 1
+#+END_SRC
** nfs-server
*** tasks
#+BEGIN_SRC yaml :tangle roles/nfs-server/tasks/main.yml :mkdirp yes
@@ -1375,6 +1394,176 @@ def main():
if __name__ == '__main__':
main()
#+END_SRC
+** xorg_facts.py
+#+BEGIN_SRC python :tangle library/xorg_facts.py
+#!/usr/bin/env python2
+
+DOCUMENTATION = '''
+---
+module: xorg_facts
+short_description: "gather facts about connected monitors and available modelines"
+description:
+ - This script needs a running x-server on a given display in order to successfully call xrandr.
+ The ranking uses the following factors:
+ 1. preferred_refreshrate
+ 2. preferred_resolution
+ 3. preferred_output
+ For each element a dictionary of values (up to 4 bit [0 .. 256]) may be passed to the module.
+ The rank is represented by this order of 4-Bit values:
+ | rrate | resolution | output | internal score
+ | 50 | 1920x1080 | HDMI | 0b_0100_0100_0100 = 1092
+ | 60 | 1280x720 | DP | 0b_0011_0011_0011 = 819
+ Returns the connected output, monitors and modelines and a suggestion for the most fitting mode in a dictionary 'xorg'
+options:
+ display:
+ required: False
+ default: ":0"
+ description:
+ - the DISPLAY variable to use when calling xrandr
+ preferred_outpus:
+ required: False
+ default: {"HDMI": 4, "DP": 3, "DVI": 2, "VGA": 1, "TV": 0}
+ description:
+ - ranking of the preferred display connectors
+ preferred_refreshrates:
+ required: False
+ default: {"50": 4, "60": 3, "75": 2, "30": 1, "25": 0}
+ description:
+ - ranking of the preferred display refreshrate
+ preferred_resolutions:
+ required: False
+ default: {"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0}
+ description:
+ - ranking of the preferred display resolutions
+'''
+EXAMPLES = '''
+- name: "collect facts for connected displays"
+ action: xserver_facts
+ display: ":0"
+
+- debug:
+ var: xorg
+'''
+
+import ast
+import json
+import re
+import subprocess
+import sys
+import time
+from collections import OrderedDict, namedtuple
+
+from ansible.module_utils.basic import *
+
+arg_specs = {
+ 'display': dict(default=[":0", ":0.1"], type='list', required=False),
+ 'multi_display': dict(default=True, type='bool', required=False),
+ 'preferred_outputs': dict(default={"HDMI": 8, "DP": 4, "DVI": 2, "VGA": 1, "TV": 0}, type='dict', required=False),
+ 'preferred_refreshrates': dict(default={50: 8, 60: 4, 75: 3, 30: 2, 25: 1}, type='dict', required=False),
+ 'preferred_resolutions': dict(default={"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0},
+ type='dict', required=False),
+ }
+
+Mode = namedtuple('Mode', ['score', 'connection', 'resolution', 'refreshrate'])
+
+
+class ModelineTools(object):
+ def __init__(self, preferred_outputs, preferred_resolutions, preferred_refreshrates):
+ self.preferred_outputs = preferred_outputs
+ self.preferred_resolutions = preferred_resolutions
+ self.preferred_refreshrates = preferred_refreshrates
+
+ def get_score(self, connection, resolution, refreshrate):
+ connection = connection.split('-')[0]
+ score = self.preferred_refreshrates.get(int(refreshrate), 0)
+ score = score << 4
+ score += self.preferred_resolutions.get(resolution, 0)
+ #score = score << 4
+ #score += self.preferred_outputs.get(connection, 0)
+ return score
+
+ @staticmethod
+ def cleanup_refreshrate(refreshrate):
+ rrate = refreshrate.replace('+', '').replace('*', '').replace(' ', '').strip()
+ return int(round(ast.literal_eval(rrate)))
+
+ def sort_mode(self, mode):
+ x, y = mode.resolution.split('x')
+ connection = mode.connection.split('-')[0]
+ return (mode.score, int(x), int(y), self.preferred_outputs.get(connection, 0))
+
+
+def main():
+ module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=False,)
+ display_list = module.params['display']
+ preferred_outputs = module.params['preferred_outputs']
+ preferred_resolutions = module.params['preferred_resolutions']
+ preferred_refreshrates = module.params['preferred_refreshrates']
+ mtools = ModelineTools(preferred_outputs, preferred_resolutions, preferred_refreshrates)
+ modes = []
+ displays = {}
+ data = {}
+
+ for display in display_list:
+ # call xrandr
+ try:
+ xrandr_data = subprocess.check_output(['xrandr', '-q','-d', display],
+ universal_newlines=True)
+ except: continue
+
+ for line in xrandr_data.splitlines():
+ if line.startswith('Screen'):
+ screen = line.split(':')[0].split()[-1]
+ screen = "Screen{}".format(screen)
+ displays[screen] = {}
+
+ elif 'connected' in line:
+ connection = line.split()[0]
+ displays[screen][connection] = {}
+ if 'disconnected' in line:
+ displays[screen][connection]['connected'] = False
+ else:
+ displays[screen][connection]['connected'] = True
+ displays[screen][connection]['modes'] = OrderedDict(
+ sorted({}.items(), key=lambda t: t.split('_')[0]))
+
+ elif line.startswith(' '):
+ fields = filter(None, re.split(r'\s{2,}', line))
+ resolution = fields[0]
+ refreshrates = fields[1:]
+ r = set()
+ for refreshrate in refreshrates:
+ refreshrate = refreshrate.strip()
+ rrate = mtools.cleanup_refreshrate(refreshrate)
+ if len(refreshrate) < 2:
+ continue
+ if '*' in refreshrate:
+ current_mode = (resolution, rrate)
+ displays[screen][connection]['current_mode'] = current_mode
+ if '+' in refreshrate:
+ preferred_mode = (resolution, rrate)
+ displays[screen][connection]['preferred_mode'] = preferred_mode
+ r.add(mtools.cleanup_refreshrate(refreshrate))
+ modes.append(Mode(score=mtools.get_score(connection, resolution, rrate), connection=connection,
+ resolution=resolution, refreshrate=rrate))
+ displays[screen][connection]['modes'][resolution] = sorted(r)
+
+
+ data['displays'] = displays
+ data['modes'] = modes
+ best_mode = max(modes, key=mtools.sort_mode)
+ data["best_mode"] = {
+ 'connection': best_mode.connection,
+ 'resolution': best_mode.resolution,
+ 'refreshrate': best_mode.refreshrate,
+ }
+
+ module.exit_json(changed=False, ansible_facts={'xorg': data})
+
+
+if __name__ == '__main__':
+ main()
+#+END_SRC
* Handlers
#+BEGIN_SRC yaml :tangle handlers/main.yml :mkdirp yes
- name: Restart Samba
diff --git a/displays.yml b/displays.yml
new file mode 100644
index 0000000..8887cbf
--- /dev/null
+++ b/displays.yml
@@ -0,0 +1,12 @@
+---
+# file: yavdr07.yml
+# this playbook sets up a complete yaVDR 0.7 installation
+
+- name: set up yaVDR
+ hosts: all
+ become: true
+ roles:
+ - display-data
+
+ handlers:
+ - include: handlers/main.yml
diff --git a/library/xorg_facts.py b/library/xorg_facts.py
new file mode 100644
index 0000000..e10c721
--- /dev/null
+++ b/library/xorg_facts.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python2
+
+DOCUMENTATION = '''
+---
+module: xorg_facts
+short_description: "gather facts about connected monitors and available modelines"
+description:
+ - This script needs a running x-server on a given display in order to successfully call xrandr.
+ The ranking uses the following factors:
+ 1. preferred_refreshrate
+ 2. preferred_resolution
+ 3. preferred_output
+ For each element a dictionary of values (up to 4 bit [0 .. 256]) may be passed to the module.
+ The rank is represented by this order of 4-Bit values:
+ | rrate | resolution | output | internal score
+ | 50 | 1920x1080 | HDMI | 0b_0100_0100_0100 = 1092
+ | 60 | 1280x720 | DP | 0b_0011_0011_0011 = 819
+ Returns the connected output, monitors and modelines and a suggestion for the most fitting mode in a dictionary 'xorg'
+options:
+ display:
+ required: False
+ default: ":0"
+ description:
+ - the DISPLAY variable to use when calling xrandr
+ preferred_outpus:
+ required: False
+ default: {"HDMI": 4, "DP": 3, "DVI": 2, "VGA": 1, "TV": 0}
+ description:
+ - ranking of the preferred display connectors
+ preferred_refreshrates:
+ required: False
+ default: {"50": 4, "60": 3, "75": 2, "30": 1, "25": 0}
+ description:
+ - ranking of the preferred display refreshrate
+ preferred_resolutions:
+ required: False
+ default: {"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0}
+ description:
+ - ranking of the preferred display resolutions
+'''
+EXAMPLES = '''
+- name: "collect facts for connected displays"
+ action: xserver_facts
+ display: ":0"
+
+- debug:
+ var: xorg
+'''
+
+import ast
+import json
+import re
+import subprocess
+import sys
+import time
+from collections import OrderedDict, namedtuple
+
+from ansible.module_utils.basic import *
+
+arg_specs = {
+ 'display': dict(default=[":0", ":0.1"], type='list', required=False),
+ 'multi_display': dict(default=True, type='bool', required=False),
+ 'preferred_outputs': dict(default={"HDMI": 8, "DP": 4, "DVI": 2, "VGA": 1, "TV": 0}, type='dict', required=False),
+ 'preferred_refreshrates': dict(default={50: 8, 60: 4, 75: 3, 30: 2, 25: 1}, type='dict', required=False),
+ 'preferred_resolutions': dict(default={"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0},
+ type='dict', required=False),
+ }
+
+Mode = namedtuple('Mode', ['score', 'connection', 'resolution', 'refreshrate'])
+
+
+class ModelineTools(object):
+ def __init__(self, preferred_outputs, preferred_resolutions, preferred_refreshrates):
+ self.preferred_outputs = preferred_outputs
+ self.preferred_resolutions = preferred_resolutions
+ self.preferred_refreshrates = preferred_refreshrates
+
+ def get_score(self, connection, resolution, refreshrate):
+ connection = connection.split('-')[0]
+ score = self.preferred_refreshrates.get(int(refreshrate), 0)
+ score = score << 4
+ score += self.preferred_resolutions.get(resolution, 0)
+ #score = score << 4
+ #score += self.preferred_outputs.get(connection, 0)
+ return score
+
+ @staticmethod
+ def cleanup_refreshrate(refreshrate):
+ rrate = refreshrate.replace('+', '').replace('*', '').replace(' ', '').strip()
+ return int(round(ast.literal_eval(rrate)))
+
+ def sort_mode(self, mode):
+ x, y = mode.resolution.split('x')
+ connection = mode.connection.split('-')[0]
+ return (mode.score, int(x), int(y), self.preferred_outputs.get(connection, 0))
+
+
+def main():
+ module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=False,)
+ display_list = module.params['display']
+ preferred_outputs = module.params['preferred_outputs']
+ preferred_resolutions = module.params['preferred_resolutions']
+ preferred_refreshrates = module.params['preferred_refreshrates']
+ mtools = ModelineTools(preferred_outputs, preferred_resolutions, preferred_refreshrates)
+ modes = []
+ displays = {}
+ data = {}
+
+ for display in display_list:
+ # call xrandr
+ try:
+ xrandr_data = subprocess.check_output(['xrandr', '-q','-d', display],
+ universal_newlines=True)
+ except: continue
+
+ for line in xrandr_data.splitlines():
+ if line.startswith('Screen'):
+ screen = line.split(':')[0].split()[-1]
+ screen = "Screen{}".format(screen)
+ displays[screen] = {}
+
+ elif 'connected' in line:
+ connection = line.split()[0]
+ displays[screen][connection] = {}
+ if 'disconnected' in line:
+ displays[screen][connection]['connected'] = False
+ else:
+ displays[screen][connection]['connected'] = True
+ displays[screen][connection]['modes'] = OrderedDict(
+ sorted({}.items(), key=lambda t: t.split('_')[0]))
+
+ elif line.startswith(' '):
+ fields = filter(None, re.split(r'\s{2,}', line))
+ resolution = fields[0]
+ refreshrates = fields[1:]
+ r = set()
+ for refreshrate in refreshrates:
+ refreshrate = refreshrate.strip()
+ rrate = mtools.cleanup_refreshrate(refreshrate)
+ if len(refreshrate) < 2:
+ continue
+ if '*' in refreshrate:
+ current_mode = (resolution, rrate)
+ displays[screen][connection]['current_mode'] = current_mode
+ if '+' in refreshrate:
+ preferred_mode = (resolution, rrate)
+ displays[screen][connection]['preferred_mode'] = preferred_mode
+ r.add(mtools.cleanup_refreshrate(refreshrate))
+ modes.append(Mode(score=mtools.get_score(connection, resolution, rrate), connection=connection,
+ resolution=resolution, refreshrate=rrate))
+ displays[screen][connection]['modes'][resolution] = sorted(r)
+
+
+ data['displays'] = displays
+ data['modes'] = modes
+ best_mode = max(modes, key=mtools.sort_mode)
+ data["best_mode"] = {
+ 'connection': best_mode.connection,
+ 'resolution': best_mode.resolution,
+ 'refreshrate': best_mode.refreshrate,
+ }
+
+ module.exit_json(changed=False, ansible_facts={'xorg': data})
+
+
+if __name__ == '__main__':
+ main()
diff --git a/localhost_inventory b/localhost_inventory
index c286796..a51c139 100644
--- a/localhost_inventory
+++ b/localhost_inventory
@@ -1,7 +1,2 @@
-[yavdr-full]
+[localhost]
localhost connection=local
-#192.168.1.116
-
-[yavdr-headless]
-
-[yavdr-client]
diff --git a/roles/display-data/tasks/main.yml b/roles/display-data/tasks/main.yml
new file mode 100644
index 0000000..ae8f802
--- /dev/null
+++ b/roles/display-data/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+# file: roles/display-data/tasks/main.yml
+
+- name: "detect xorg configuration"
+ action: xorg_facts
+
+- debug:
+ var: xorg
+ verbosity: 1
diff --git a/roles/template-test/defaults/main.yml b/roles/template-test/defaults/main.yml
new file mode 100644
index 0000000..da426aa
--- /dev/null
+++ b/roles/template-test/defaults/main.yml
@@ -0,0 +1,22 @@
+foo:
+ - bar
+ - baz
+ - spam
+
+system:
+ hardware:
+ nvidia:
+ detected: "1"
+ busid: "000:2304:234"
+ x11:
+ dualhead:
+ enabled: "0"
+ display:
+ 0:
+ mode:
+ - "1920x1080_50"
+ default: "nvidia-auto"
+
+ 1:
+ mode:
+ - "1280x720_60"
diff --git a/roles/template-test/tasks/main.yml b/roles/template-test/tasks/main.yml
new file mode 100644
index 0000000..a2a30b2
--- /dev/null
+++ b/roles/template-test/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+- name: show vars
+ debug:
+ var: '{{ system }}'
+
+- name: test templates
+ template:
+ src: templates/test.j2
+ dest: /tmp/test.txt
diff --git a/roles/template-test/templates/test.j2 b/roles/template-test/templates/test.j2
new file mode 100644
index 0000000..dd84b0e
--- /dev/null
+++ b/roles/template-test/templates/test.j2
@@ -0,0 +1,184 @@
+{{ ansible_managed_file | comment }}
+
+Section "ServerLayout"
+ Identifier "Layout0"
+ Screen 0 "Screen0"
+ {% if system.x11.dualhead.enabled %}
+ Screen 1 "Screen1" RightOf "Screen0"
+ {% endif %}
+ InputDevice "Keyboard0" "CoreKeyboard"
+ InputDevice "Mouse0" "CorePointer"
+EndSection
+
+Section "InputDevice"
+ # generated from default
+ Identifier "Mouse0"
+ Driver "mouse"
+ Option "Protocol" "auto"
+ Option "Device" "/dev/psaux"
+ Option "Emulate3Buttons" "no"
+ Option "ZAxisMapping" "4 5"
+EndSection
+
+
+Section "InputDevice"
+ # generated from default
+ Identifier "Keyboard0"
+ Driver "kbd"
+EndSection
+
+
+Section "Monitor"
+ Identifier "Monitor0"
+ VendorName "Unknown"
+ ModelName "Unknown"
+{% if system.x11.display.0.default == "VGA2Scart_4_3" or system.x11.display.0.default == "VGA2Scart_16_9" %}
+ HorizSync 14-17
+ VertRefresh 49-61
+ {% if system.x11.display.0.default == "VGA2Scart_4_3" %}
+ Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
+ {% elif system.x11.display.0.default == "VGA2Scart_16_9" %}
+ Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
+ {% endif %}
+{% endif %}
+ Option "DPMS"
+ Option "ExactModeTimingsDVI" "True"
+EndSection
+
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Monitor"
+ Identifier "Monitor1"
+ VendorName "Unknown"
+ ModelName "Unknown"
+{% if system.x11.display.1.default in ("VGA2Scart_4_3", "VGA2Scart_16_9") %}
+ HorizSync 14-17
+ VertRefresh 49-61
+ {% if system.x11.display.1.default == "VGA2Scart_4_3" %}
+ Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
+ {% elif system.x11.display.1.default == "VGA2Scart_16_9" %}
+ Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
+ {% endif %}
+ Option "DPMS"
+ Option "ExactModeTimingsDVI" "True"
+{% endif %}
+EndSection
+{% endif %}
+
+Section "Device"
+ Identifier "Device0"
+{% if system.hardware.nvidia.detected %}
+ Driver "nvidia"
+ VendorName "NVIDIA Corporation"
+{% endif %}
+ Screen 0
+ Option "DPI" "100x100"
+{% if system.hardware.nvidia.busid %}
+ BusID "PCI: {{ system.hardware.nvidia.busid }}"
+{% endif %}
+ Option "NoLogo" "True"
+ Option "UseEvents" "True"
+ Option "TripleBuffer" "False"
+ Option "AddARGBGLXVisuals" "True"
+ Option "TwinView" "0"
+ Option "DynamicTwinView" "0"
+ Option "OnDemandVBlankinterrupts" "on"
+ Option "FlatPanelProperties" "Scaling = Native"
+EndSection
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Device"
+ Identifier "Device1"
+ {% if system.hardware.nvidia.detected %}
+ Driver "nvidia"
+ VendorName "NVIDIA Corporation"
+ {% endif %}
+ Screen 1
+ {% if system.hardware.nvidia.busid %}
+ BusID "PCI: {{ system.hardware.nvidia.busid }}"
+ {% endif %}
+ Option "NoLogo" "True"
+ Option "UseEvents" "True"
+ Option "TripleBuffer" "False"
+ Option "AddARGBGLXVisuals" "True"
+ Option "TwinView" "0"
+ Option "DynamicTwinView" "0"
+EndSection
+{% endif %}
+
+
+Section "Screen"
+ Identifier "Screen0"
+ Device "Device0"
+ Monitor "Monitor0"
+ DefaultDepth 24
+ SubSection "Display"
+ Depth 24
+{% if system.x11.display.0.default is defined and system.x11.display.0.default %}
+ Modes "{{ system.x11.display.0.default }}"{% for mode in system.x11.display.0.mode %}{% if mode != system.x11.display.0.default %} "{{ mode }}"{% endif %}{% endfor %}
+
+{% elif system.hardware.nvidia.detected == 1 %}
+ Modes "nvidia-auto-select"
+{% endif %}
+ EndSubSection
+{% if system.x11.display.0.default or system.x11.default %}
+ {% if system.x11.display.0.device is definded and system.x11.display.0.device %}
+ Option "ConnectedMonitor" {{ system.x11.display.0.device }}
+ {% else %}
+ Option "ConnectedMonitor" {{ system.x11.default }}
+ {% endif %}
+ # Option "ConnectedMonitor" ", "
+ #Option "ConnectedMonitor"
+ "
+
+
+
+
+ , "
+# Option "UseDisplayDevice" ""
+#
+#
+# Option "CustomEDID" ":/etc/X11/edid.0.yavdr"
+#
+#
+# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }"
+#
+# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }"
+{% endif %}
+EndSection
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Screen"
+
+ Identifier "Screen1"
+ Device "Device1"
+ Monitor "Monitor1"
+ DefaultDepth 24
+ SubSection "Display"
+ Depth 24
+{% if system.x11.display.0.default is defined and system.x11.display.0.default %}
+ Modes "{{ system.x11.display.1.default }}"{% for mode in system.x11.display.1.mode %}{% if mode != system.x11.display.1.default %} "{{ mode }}"{% endif %}{% endfor %}
+
+{% elif system.hardware.nvidia.detected == "1" %}
+ Modes "nvidia-auto-select"
+{% endif %}
+ EndSubSection
+
+#
+# Option "UseDisplayDevice" ""
+#
+#
+# Option "CustomEDID" ":/etc/X11/edid.1.yavdr"
+#
+#
+# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }"
+#
+# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }"
+#
+EndSection
+{% endif %}
+
+Section "Extensions"
+# if no open-gl OSD is needed (e.g. for vdr-sxfe):
+ Option "Composite" "Disable"
+EndSection
diff --git a/roles/template-test/vars/main.yml b/roles/template-test/vars/main.yml
new file mode 100644
index 0000000..0f734b8
--- /dev/null
+++ b/roles/template-test/vars/main.yml
@@ -0,0 +1,5 @@
+vars:
+ foo:
+ - bar
+ - baz
+ - spam
diff --git a/roles/yavdr-xorg/templates/x-verbose.service.j2 b/roles/yavdr-xorg/templates/x-verbose.service.j2
new file mode 100644
index 0000000..028dc95
--- /dev/null
+++ b/roles/yavdr-xorg/templates/x-verbose.service.j2
@@ -0,0 +1,8 @@
+[Unit]
+Description=X with verbose logging on %I
+Wants=graphical.target
+Before=graphical.target
+
+[Service]
+Type=forking
+ExecStart=/usr/bin/x-daemon -logverbose 6 -noreset %I