# -*- mode: org; -*- :DOCUMENT_OPTIONS: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+OPTIONS: ^:nil #+PROPERTY: header-args :mkdirp yes :END: * Installing and configuring yaVDR with Ansible This is an experimental feature which allows to set up a yaVDR installation based on a normal Ubuntu Server 16.04.x installation using [[http://ansible.com][Ansible]]. This Manual is written in org-mode for Emacs and can rewrite the complete ansible configuration if you call ~org-babel-tangle~ from within emacs. To use this playbook on a Ubuntu Server Installation you need to run the following commands: #+BEGIN_SRC shell sudo apt-get install git git clone https://github.com/yavdr/yavdr-ansible.git cd yavdr-ansible sudo ./install-yavdr.sh #+END_SRC ** Install script for local usage #+BEGIN_SRC shell :tangle install-yavdr.sh :shebang "#!/bin/bash" if (( $EUID != 0 )); then echo "This script must be run using sudo or as root" exit fi apt-get -y install software-properties-common # Add repository for ansible add-apt-repository -y ppa:ansible/ansible # update packages apt-get update # install required packages apt-get -y install ansible # TODO: run ansible on local host ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local #+END_SRC * Playbooks ** yavdr07.yml The ~yavdr07.yml~ playbook sets up a fully-featured yaVDR installation: #+BEGIN_SRC yaml :tangle yavdr07.yml :mkdirp yes --- # file: yavdr07.yml # this playbook sets up a complete yaVDR 0.7 installation - name: set up yaVDR hosts: all become: true roles: - yavdr-common # install and configure the basic system - vdr # install vdr and related packages - yavdr-network # enable network client capabilities - samba-install # install samba server - samba-config # configure samba server - nfs-server # install nfs server - yavdr-xorg # graphical session - yavdr-remote # remote configuration files, services and scripts - grub-config # configure grub - autoinstall-satip # install vdr-plugin-satip if a Sat>IP server has been found - autoinstall-targavfd - autoinstall-imonlcd #- template-test handlers: - include: handlers/main.yml #+END_SRC ** yavdr07-headless.yml For a headless server installation ~yavdr07-headless.yml~ is a good choice #+BEGIN_SRC yaml :tangle yavdr07-headless.yml :mkdirp yes --- # file: yavdr07-headless.yml # this playbook set up a headless yaVDR 0.7 installation - name: set up a headless yaVDR server hosts: all become: true roles: - yavdr-common - vdr - yavdr-network - samba-server - samba-config - nfs-server - grub-config - autoinstall-satip handlers: - include: handlers/main.yml #+END_SRC * Hosts 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 connection=local #192.168.1.116 [yavdr-headless] [yavdr-client] #+END_SRC * Group Variables ** default text for templates #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes # file: group_vars/all # this is the standard text to put in templates ansible_managed_file: "*** YAVDR: ANSIBLE MANAGED FILE ***" #+END_SRC ** PPAs #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes branch: unstable ppa_owner: 'ppa:yavdr' # a list of all package repositories to be added to the installation repositories: - '{{ ppa_owner }}/main' - '{{ ppa_owner }}/unstable-main' - '{{ ppa_owner }}/{{branch}}-vdr' - '{{ ppa_owner }}/{{branch}}-yavdr' - '{{ ppa_owner }}/{{branch}}-kodi' #+END_SRC ** Drivers #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes drivers: sundtek: auto ddvb-dkms: auto #+END_SRC ** VDR user, directories, special configuration and plugins #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes # properties of the user vdr and vdr-related options vdr: user: vdr group: vdr uid: 666 gid: 666 home: /var/lib/vdr recdir: /srv/vdr/video hide_first_recording_level: false safe_dirnames: true # escape characters (useful for windows clients and FAT/NTFS file systems) override_vdr_charset: false # add the vdr plugins you want to install vdr_plugins: - vdr-plugin-devstatus - vdr-plugin-markad - vdr-plugin-restfulapi - vdr-plugin-softhddevice #+END_SRC ** Media directories #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes # dictionary of directories for (shared) files. Automatically exported via NFS and Samba if those roles are enabled media_dirs: audio: /srv/audio video: /srv/audio pictures: /srv/picture files: /srv/files backups: /srv/backups recordings: '{{ vdr.recdir }}' #+END_SRC ** NFS #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes nfs: insecure: false # required for OS X clients and when using libnfs as unprivileged user (e.g. KODI) #+END_SRC ** Samba #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes samba: workgroup: YAVDR windows_compatible: '{{ vdr.safe_dirnames }}' # disable unix extensions, enable follow symlinks and wide links #+END_SRC ** Additional packages #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes # additional packages you want to install extra_packages: - vim - tree - w-scan - bpython3 #+END_SRC ** System pre-configuration #+BEGIN_SRC yaml :tangle group_vars/all :mkdirp yes #system: # shutdown: poweroff grub: timeout: 0 boot_options: quiet nosplash #+END_SRC * Roles ** yavdr-common This role is used to set up a basic yaVDR installation. It creates the directories, installs the vdr and other useful packages. *** default variables This section is for reference only, please use the files in ~global_vars~ for customizations. #+BEGIN_SRC yaml :tangle roles/yavdr-common/defaults/main.yml :mkdirp yes --- # file: roles/yavdr-common/defaults/main.yml #+END_SRC **** Repositories You can set a list of package repositories which provide the necessary packages. Feel free to use own PPAs if you need special customization to the VDR and it's plugins. #+BEGIN_SRC yaml :tangle roles/yavdr-common/defaults/main.yml :mkdirp yes branch: unstable repositories: - 'ppa:yavdr/main' - 'ppa:yavdr/unstable-main' - 'ppa:yavdr/{{branch}}-vdr' - 'ppa:yavdr/{{branch}}-kodi' - 'ppa:yavdr/{{branch}}-yavdr' #+END_SRC **** Drivers Automatically installed drivers can be very useful, but if you know you need a certain driver, you can simply set it's value to *true*. If you don't want a driver to be installed, set it's value to *false*. #+BEGIN_SRC yaml :tangle roles/yavdr-common/defaults/main.yml :mkdirp yes drivers: sundtek: auto ddvb-dkms: auto #+END_SRC **** Additional Packages Add additional packages you would like to have on your installation to this list #+BEGIN_SRC yaml :tangle roles/yavdr-common/defaults/main.yml :mkdirp yes extra_packages: - vim - tree - w-scan #+END_SRC **** VDR This section allows you to set the recording directory, the user and group that runs the vdr and it's home directory. - user :: the vdr user name - group :: the main group for the user vdr - uid :: the user id for the user vdr - gid :: the group id for the group vdr - home :: the home directory for the user vdr - recdir :: the recording directory used by VDR - hide_first_recording_level :: let vdr hide the first directory level of it's recording directory so the content of multiple directories is shown merged together - safe_dirnames :: replace special characters which are not compatible with Windows file systems and Samba shares - override_vdr_charset :: workaround for channels with weird EPG encodings, e.g. Sky #+BEGIN_SRC yaml :tangle roles/yavdr-common/defaults/main.yml :mkdirp yes vdr: user: vdr group: vdr uid: 666 gid: 666 home: /var/lib/vdr recdir: /srv/vdr/video hide_first_recording_level: false safe_dirnames: true override_vdr_charset: false #+END_SRC *** tasks yavdr-common executes the following tasks: **** main.yml #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :exports none :mkdirp yes --- # This playbook sets up the basic packages an directories for a yaVDR installation # file: roles/yavdr-common/tasks/main.yml #+END_SRC ***** Disable default installation of recommended packages This task prevents apt to automatically install all recommended dependencies for packages: #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: apt | prevent automatic installation of recommended packages template: src: templates/90-norecommends.j2 dest: /etc/apt/apt.conf.d/90norecommends #+END_SRC ***** Use bash instead of dash #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: use bash instead of dash shell: | echo "set dash/sh false" | debconf-communicate dpkg-reconfigure -f noninteractive dash #+END_SRC ***** create user vdr #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :exports none :mkdirp yes - name: create vdr group group: gid: '{{ vdr.gid }}' state: present name: '{{ vdr.group }}' - name: create vdr user user: name: '{{ vdr.user }}' group: '{{ vdr.group }}' uid: '{{ vdr.uid }}' home: '{{ vdr.home }}' shell: '/bin/bash' state: present append: true #+END_SRC ***** Disable release-upgrade notifications #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: disable release-upgrade notifications lineinfile: dest: /etc/update-manager/release-upgrades backrefs: yes state: present regexp: '^(Prompt=).*$' line: '\1never' #+END_SRC ***** Set up package repositories #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: add yaVDR PPAs apt_repository: repo: '{{ item }}' state: present update_cache: yes with_items: '{{ repositories }}' - name: upgrade existing packages apt: upgrade: dist update_cache: yes #+END_SRC ***** Install essential packages #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: apt | install basic packages apt: name: '{{ item }}' state: present install_recommends: no with_items: - anacron - at - bash-completion - biosdevname - linux-firmware - psmisc - python-kmodpy - python-usb - python3-usb - software-properties-common - ssh - ubuntu-drivers-common - wget - wpasupplicant - usbutils - xfsprogs #+END_SRC ***** Install additional packages (user defined) #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml - name: apt | install extra packages apt: name: '{{ item }}' state: present install_recommends: no with_items: '{{ extra_packages }}' #+END_SRC ***** Gather facts with custom modules #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - name: get information about usb and pci hardware and loaded kernel modules hardware_facts: usb: True pci: True modules: True gpus: True - debug: var: usb verbosity: 1 - debug: var: pci verbosity: 1 - debug: var: modules verbosity: 1 - debug: var: gpus verbosity: 1 - name: "detect SAT>IP Server on the network" action: satip_facts - debug: var: satip_detected verbosity: 1 #+END_SRC ***** create media directories #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :exports none :mkdirp yes - name: create media directories file: dest: '{{ item.value }}' owner: '{{ vdr.user }}' group: '{{ vdr.group }}' state: directory mode: '0777' with_dict: '{{ media_dirs }}' #+END_SRC *** templates #+BEGIN_SRC c :tangle roles/yavdr-common/templates/90-norecommends.j2 :mkdirp yes {{ ansible_managed_file | comment('c') }} // Recommends are as of now still abused in many packages APT::Install-Recommends "0"; APT::Install-Suggests "0"; #+END_SRC ** vdr *** tasks **** install the basic vdr packages #+BEGIN_SRC yaml :tangle roles/vdr/tasks/main.yml :mkdirp yes --- # file: roles/vdr/tasks/main.yml - name: apt | install basic vdr packages apt: name: '{{ item }}' state: present install_recommends: no with_items: - vdr - vdrctl - vdr-plugin-dbus2vdr #+END_SRC **** Add svdrp/svdrp-disc to /etc/services #+BEGIN_SRC yaml :tangle roles/vdr/tasks/main.yml :mkdirp yes - name: add svdrp to /etc/services lineinfile: dest: /etc/services state: present line: "svdrp 6419/tcp" - name: add svdrp-disc to /etc/services lineinfile: dest: /etc/services state: present line: "svdrp-disc 6419/udp" #+END_SRC **** Set up the recording directory for the vdr user #+BEGIN_SRC yaml :tangle roles/vdr/tasks/main.yml :mkdirp yes - name: create vdr recdir file: state: directory owner: '{{ vdr.user }}' group: '{{ vdr.group }}' mode: 0775 dest: '{{ vdr.recdir }}' - name: set option to use hide-first-recording-level patch blockinfile: dest: /etc/vdr/conf.d/04-vdr-hide-first-recordinglevel.conf create: true block: | [vdr] --hide-first-recording-level when: vdr.hide_first_recording_level - name: create local dir in recdir file: state: directory owner: '{{ vdr.user }}' group: '{{ vdr.group }}' mode: '0775' dest: '{{ vdr.recdir }}/local' when: vdr.hide_first_recording_level # TODO: set recdir, user etc. in /etc/vdr/conf.d/ #+END_SRC **** Install additional vdr plugins The additional plugins to install can be set in the variable ~{{vdr_plugins}}~ in the group variables #+BEGIN_SRC yaml :tangle roles/vdr/tasks/main.yml :mkdirp yes - name: apt | install additional vdr plugins apt: name: '{{ item }}' state: present install_recommends: no with_items: '{{ vdr_plugins | default({}) }}' notify: [ 'Restart VDR' ] #+END_SRC ** STARTED yavdr-network *** default variables #+BEGIN_SRC yaml :tangle roles/yavdr-network/main.yml :mkdirp yes install_avahi: true #+END_SRC *** tasks #+BEGIN_SRC yaml :tangle roles/yavdr-network/tasks/main.yml :mkdirp yes --- # this playbook sets up network services for a yaVDR installation # - name: install network packages apt: name: '{{ item }}' state: present install_recommends: no with_items: - avahi-daemon - avahi-utils - biosdevname - ethtool - nfs-common - vdr-addon-avahi-linker - wakeonlan # Does this really work? We need a way to check if an interface supports WOL - Python Skript? # - name: check WOL capabilities of network interfaces # shell: 'ethtool {{ item }} | grep -Po "(?<=Supports\sWake-on:\s).*$"' # register: wol # with_items: '{% for interface in ansible_interfaces if interface != 'lo' and interface != 'bond0' %}' #+END_SRC ** STARTED nfs-server *** tasks #+BEGIN_SRC yaml :tanlge roles/nfs-server/tasks/main.yml :mkdirp yes - name: install and configure nfs-kernel-server apt: name: "{{ item }}" state: present install_recommends: no with_items: - nfs-kernel-server when: - '{{ install_nfs_server }}' #+END_SRC ** TODO yavdr-remote *** default variables *** tasks *** templates *** files ** TODO automatic X-server configuration - [ ] detect connected display - [ ] read EDID from displays - [ ] create a xorg.conf for nvidia/intel/amd gpus *** templates #+BEGIN_SRC conf :tangle roles/yavdr-xorg/templates/vdr-xorg.conf :mkdirp yes # file: roles/yavdr-xorg/templates/vdr-xorg.conf # {{ ansible_managed_file }} [Unit] After=x@vt7.service Wants=x@vt7.service BindsTo=x@vt7.service #+END_SRC #+BEGIN_SRC shell :tangle roles/yavdr-xorg/templates/.xinitrc.j2 :mkdirp yes #!/bin/bash # {{ ansible_managed_file }} exec openbox-session #+END_SRC #+BEGIN_SRC shell tangle: ansible/yavdr-ansible/roles/yavdr-xorg/templates/autostart.j2 :mkdirp yes env | grep "DISPLAY\|DBUS_SESSION_BUS_ADDRESS\|XDG_RUNTIME_DIR" > ~/.session-env systemctl --user import-environment #+END_SRC *** files ** yavdr-xorg *** default variables *** tasks #+BEGIN_SRC yaml :tangle roles/yavdr-xorg/tasks/main.yml :mkdirp yes --- # file: roles/yavdr-xorg/tasks/main.yml - name: install packages for xorg apt: name: '{{ item }}' state: present with_items: - xorg - xserver-xorg-video-all - xserver-xorg-input-all - xlogin - xterm #- yavdr-xorg - openbox - name: create folders for user session file: state: directory dest: '{{ item }}' mode: '0775' owner: '{{ vdr.user }}' group: '{{ vdr.group }}' with_items: - '{{ vdr.home }}/.config/systemd/user' - '{{ vdr.home }}/.config/openbox/autostart' ### TODO: move to yavdr-xorg package? ### - name: create folder for customizations of vdr.service file: state: directory dest: /etc/systemd/system/vdr.service.d mode: '0775' - name: add dependency to X-server for vdr.service using a drop-in template: src: templates/vdr-xorg.conf dest: /etc/systemd/system/vdr.service.d/ ### END TODO ### - name: create .xinitrc for vdr user template: src: 'templates/.xinitrc.j2' dest: '/var/lib/vdr/.xinitrc' mode: 0755 owner: '{{ vdr.user }}' group: '{{ vdr.group }}' - name: populate autostart for openbox template: src: 'templates/autostart.j2' dest: '/var/lib/vdr/.config/openbox/autostart' mode: 0755 owner: '{{ vdr.user }}' group: '{{ vdr.group }}' - name: set a login shell for the user vdr user: name: '{{ vdr.user }}' shell: '/bin/bash' state: present uid: '{{ vdr.uid }}' groups: '{{ vdr.group }}' append: yes - name: enable and start xlogin for the user vdr systemd: daemon_reload: yes name: 'xlogin@{{ vdr.user }}' enabled: yes state: started #+END_SRC ** nfs-server *** tasks #+BEGIN_SRC yaml :tangle roles/nfs-server/tasks/main.yml :mkdirp yes - name: install nfs server packages apt: name: '{{ item }}' state: present install_recommends: no with_items: - nfs-kernel-server - nfs-common - name: create /etc/exports template: src: templates/nfs-exports.j2 dest: /etc/exports notify: [ 'Restart NFS Kernel Server' ] #+END_SRC *** templates #+BEGIN_SRC conf :tangle roles/nfs-server/templates/nfs-exports.j2 :mkdirp yes /srv *(rw,fsid=0,sync,no_subtree_check,all_squash,anongid={{ vdr.gid }},anonuid={{ vdr.uid }}) {% for name, path in media_dirs.iteritems() %} {{ path }} *(rw,fsid={{ loop.index }},sync,no_subtree_check,all_squash,anongid={{ vdr.gid }},anonuid={{ vdr.uid }}{{ ',insecure' if nfs.insecure else '' }}) {% endfor %} #+END_SRC ** nfs-config ** samba-install *** tasks #+BEGIN_SRC yaml :tangle roles/samba-install/tasks/main.yml :mkdirp yes # file: roles/samba-install/tasks/main.yml - name: install samba server apt: name: '{{ item }}' state: present install_recommends: no with_items: - samba - samba-common - samba-common-bin - tdb-tools #+END_SRC ** samba-config *** tasks #+BEGIN_SRC yaml :tangle roles/samba-config/tasks/main.yml :mkdirp yes # file: roles/samba-config/tasks/main.yml # TODO: #- name: divert original smbd.conf - name: touch smb.conf.custom file: state: touch dest: '/etc/samba/smb.conf.custom' notify: [ 'Restart Samba' ] - name: expand template for smb.conf template: src: 'templates/smb.conf.j2' dest: '/etc/samba/smb.conf' #validate: 'testparm -s %s' notify: [ 'Restart Samba' ] #+END_SRC *** templates **** smb.conf ***** global settings #+BEGIN_SRC yaml :tangle roles/samba-config/templates/smb.conf.j2 :mkdirp yes # {{ ansible_managed_file }} #======================= Global Settings ======================= [global] ## Browsing/Identification ### # Change this to the workgroup/NT-domain name your Samba server will part of workgroup = {{ samba.workgroup }} # server string is the equivalent of the NT Description field server string = %h server (Samba, Ubuntu) # This will prevent nmbd to search for NetBIOS names through DNS. dns proxy = no #### Debugging/Accounting #### # This tells Samba to use a separate log file for each machine # that connects log file = /var/log/samba/log.%m # Cap the size of the individual log files (in KiB). max log size = 1000 # We want Samba to log a minimum amount of information to syslog. Everything # should go to /var/log/samba/log.{smbd,nmbd} instead. If you want to log # through syslog you should set the following parameter to something higher. syslog = 0 # Do something sensible when Samba crashes: mail the admin a backtrace panic action = /usr/share/samba/panic-action %d ####### Authentication ####### # "security = user" is always a good idea. This will require a Unix account # in this server for every user accessing the server. See # /usr/share/doc/samba-doc/htmldocs/Samba3-HOWTO/ServerType.html # in the samba-doc package for details. # security = user # You may wish to use password encryption. See the section on # 'encrypt passwords' in the smb.conf(5) manpage before enabling. encrypt passwords = true # If you are using encrypted passwords, Samba will need to know what # password database type you are using. passdb backend = tdbsam obey pam restrictions = yes # This boolean parameter controls whether Samba attempts to sync the Unix # password with the SMB password when the encrypted SMB password in the # passdb is changed. unix password sync = yes # For Unix password sync to work on a Debian GNU/Linux system, the following # parameters must be set (thanks to Ian Kahan < for # sending the correct chat script for the passwd program in Debian Sarge). passwd program = /usr/bin/passwd %u passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . # This boolean controls whether PAM will be used for password changes # when requested by an SMB client instead of the program listed in # 'passwd program'. The default is 'no'. pam password change = yes # This option controls how unsuccessful authentication attempts are mapped # to anonymous connections map to guest = bad user {% if samba.windows_compatible %} # disable unix extensions and enable following symlinks unix extensions = no follow symlinks= yes wide links= yes {% endif %} #+END_SRC ***** media directories #+BEGIN_SRC yaml :tangle roles/samba-config/templates/smb.conf.j2 :mkdirp yes {% for name, path in media_dirs.iteritems() %} [{{ name }}] path = {{ path }} comment = {{ name }} on %h guest ok = yes writeable = yes browseable = yes create mode = 0664 directory mode = 0775 force user = {{ vdr.user }} force group = {{ vdr.group }} follow symlinks = yes wide links = yes {% endfor %} #+END_SRC ***** include custom samba exports #+BEGIN_SRC yaml :tangle roles/samba-config/templates/smb.conf.j2 :mkdirp yes include = /etc/samba/smb.conf.custom #+END_SRC ** grub-config *** default variables #+BEGIN_SRC yaml :tangle roles/grub-config/defaults/main.yml :mkdirp yes system: shutdown: poweroff grub: timeout: 0 boot_options: quiet nosplash #+END_SRC *** tasks #+BEGIN_SRC yaml :tangle roles/grub-config/tasks/main.yml :mkdirp yes - name: custom grub configuration for timeout and reboot halt template: src: templates/50_custom.j2 dest: /etc/grub.d/50_custom mode: '0775' notify: [ 'Update GRUB' ] # TODO: add special case if plymouth is used - name: let the system boot quietly lineinfile: dest: /etc/default/grub state: present regexp: '^(GRUB_CMDLINE_LINUX_DEFAULT=")' line: '\1{{ grub.boot_options}}"' backrefs: yes notify: [ 'Update GRUB' ] #+END_SRC *** templates #+BEGIN_SRC shell :tangle roles/grub-config/templates/50_custom.j2 :mkdirp yes #!/bin/sh exec tail -n +3 $0 # This file is configured by the ansible configuration for yaVDR {% if system.shutdown is defined and system.shutdown == 'reboot' %} menuentry "PowerOff" { halt } {% endif %} if [ "${recordfail}" = 1 ]; then set timeout={{ 3 if grub.timeout < 3 else grub.timeout }} else set timeout={{ grub.timeout if grub.timeout is defined else 0 }} fi #+END_SRC *** handlers #+BEGIN_SRC yaml :tangle roles/grub-config/handlers/main.yml :mkdirp yes - name: Update GRUB command: update-grub failed_when: ('error' in grub_register_update.stderr) register: grub_register_update # TODO: Do we need to use grub-set-default? # https://github.com/yavdr/yavdr-utils/blob/master/events/actions/update-grub #+END_SRC ** TODO autoinstall-drivers *** sundtek ** autoinstall-satip *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-satip/tasks/main.yml --- # file roles/autoinstall-satip/tasks/main.yml - name: apt | install vdr-plugin-satip if a Sat>IP server has been detected apt: name: vdr-plugin-satip when: satip_detected #+END_SRC ** autoinstall-targavfd *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-targavfd/tasks/main.yml --- # file roles/autoinstall-targavfd/tasks/main.yml - name: apt | install vdr-plugin-targavfd if connected apt: name: vdr-plugin-targavfd when: - '"19c2:6a11" in usb' #+END_SRC ** autoinstall-imonlcd *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-imonlcd/tasks/main.yml --- # file roles/autoinstall-imonlcd/tasks/main.yml - name: apt | install vdr-plugin-imonlcd if connected apt: name: vdr-plugin-imonlcd when: - '"15c2:0038" in usb' - '"15c2:ffdc" in usb' #+END_SRC ** autoinstall-libcecdaemon *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-libcecdaemon/tasks/main.yml --- # file roles/autoinstall-libcec-daemon/tasks/main.yml - name: apt | install libcec-daemon if connected apt: name: libcec-daemon when: - '"2548:1002" in usb' #+END_SRC ** autoinstall-pvr350 *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-pvr350/tasks/main.yml --- # file roles/autoinstall-pvr350/tasks/main.yml - name: apt | install vdr-plugin-pvr350 if connected apt: name: vdr-plugin-pvr350 when: - '19c2:6a11" in pci' #+END_SRC ** TODO autoinstall-dvbhddevice Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware sollte in yavdr-firmware stecken *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-dvbhddevice/tasks/main.yml --- # file roles/autoinstall-dvbhddevice/tasks/main.yml - name: apt | install vdr-plugin-dvbhddevice if connected apt: name: vdr-plugin-dvbhddevice when: - '"13c2:300a" in pci' - '"13c2:300b" in pci' #+END_SRC ** autoinstall-dvbsddevice *** tasks #+BEGIN_SRC yaml :tangle roles/autoinstall-dvbsddevice/tasks/main.yml --- # file roles/autoinstall-dvbsddevice/tasks/main.yml - name: apt | install vdr-plugin-dvbsddevice if module is loaded apt: name: vdr-plugin-dvbsddevice when: - '19c2:6a11" in modules' #+END_SRC ** TODO autoinstall-plugins *** sddevice *** hddevice *** pvr350 ** template-test #+BEGIN_SRC yaml :tangle roles/template-test/tasks/main.yml --- - name: show vars debug: var: '{{ system }}' - name: test templates template: src: templates/test.j2 dest: /tmp/test.txt #+END_SRC #+BEGIN_SRC shell :tangle roles/template-test/templates/test.j2 {{ 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 #+END_SRC #+BEGIN_SRC yaml :tangle roles/template-test/defaults/main.yml 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" #+END_SRC * Modules This section contains custom modules for the yaVDR Playbooks. They are used to collect facts about the system and configure applications and daemons. ** hardware_facts.py #+BEGIN_SRC python :tangle library/hardware_facts.py #!/usr/bin/env python # This Module collects the vendor- and device ids for USB- and PCI(e)-devices and currently loaded kernel modules. DOCUMENTATION = ''' --- module: hardware_facts short_description: collects facts for kernel modules, usb and pci devices description: - This Module collects the vendor- and device ids for USB- and PCI(e)-devices and currently loaded kernel modules. options: usb: required: False default: True description: - return a list of vendor- and device ids for usb devices in '04x:04x' notation pci: required: False default: True description: - return a list of vendor- and device ids for pci devices in '04x:04x' notation modules: required: False default: True description: - return a list of currently loaded kernel modules gpus: required: False default: True description: - return a list of devices of the pci gpu class (0x030000) notes: - requres python-pyusb and python-kmodpy requirements: [ ] author: "Alexander Grothe " ''' EXAMPLES = ''' - name: get information about usb and pci hardware and loaded kernel modules hardware_facts: usb: True pci: True modules: True - debug: var: usb - debug var: pci - debug var: modules - debug var: gpus ''' import glob import json import os import sys import usb.core from collections import namedtuple import kmodpy from ansible.module_utils.basic import * PCIDevice = namedtuple("PCIDevice", ['idVendor', 'idProduct', 'idClass']) def get_pci_devices(): for device in glob.glob('/sys/devices/pci*/*:*:*/'): with open(os.path.join(device, 'device')) as d: product_id = int(d.read().strip(), 16) with open(os.path.join(device, 'vendor')) as d: vendor_id = int(d.read().strip(), 16) with open(os.path.join(device, 'class')) as d: class_id = int(d.read().strip(), 16) yield PCIDevice(idVendor=vendor_id, idProduct=product_id, idClass=class_id) def format_device_list(iterator): return ["{:04x}:{:04x}".format(d.idVendor, d.idProduct) for d in iterator] def format_gpu_device_list(iterator): def get_entries(iterator): for d in iterator: if d.idClass == 0x030000: yield ("{:04x}:{:04x}".format(d.idVendor, d.idProduct)) return [entry for entry in get_entries(iterator)] arg_specs = { 'usb': dict(default=True, type='bool', required=False), 'pci': dict(default=True, type='bool', required=False), 'modules': dict(default=True, type='bool', required=False), 'gpus': dict(default=True, type='bool', required=False), } def main(): module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=True,) collect_usb = module.params['usb'] collect_pci = module.params['pci'] collect_modules = module.params['modules'] collect_gpus = module.params['gpus'] if collect_usb: usb_devices = format_device_list(usb.core.find(find_all=True)) else: usb_device = [] if collect_pci: pci_devices = format_device_list(get_pci_devices()) else: pci_devices = [] if collect_modules: k = kmodpy.Kmod() modules = [m[0] for m in k.loaded()] else: modules = [] if collect_gpus: gpus = format_gpu_device_list(get_pci_devices()) else: gpus = [] data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus} module.exit_json(changed=False, ansible_facts=data, msg=data) if __name__ == '__main__': main() #+END_SRC ** satip_facts.py #+BEGIN_SRC python :tangle library/satip_facts.py #!/usr/bin/env python2 DOCUMENTATION = ''' --- module: hardware_facts short_description: "check if at least one SAT>IP server responds on the network" description: - This script sends a multicast message and awaits responses by Sat>IP servers. Returns the boolean variable 'satip_detected' ''' EXAMPLES = ''' - name: "detect SAT>IP Server on the network" action: satip_facts - debug: var: satip_detected ''' import json import socket import sys import time from ansible.module_utils.basic import * SSDP_ADDR = "239.255.255.250" SSDP_PORT = 1900 # SSDP_MX = max delay for server response # a value of 2s is recommended by the SAT>IP specification 1.2.2 SSDP_MX = 2 SSDP_ST = "urn:ses-com:device:SatIPServer:1" ssdpRequest = "\r\n".join(( "M-SEARCH * HTTP/1.1", "HOST: %s:%d" % (SSDP_ADDR, SSDP_PORT), "MAN: \"ssdp:discover\"", "MX: %d" % (SSDP_MX), "ST: %s" % (SSDP_ST), "\r\n")) def main(): module = AnsibleModule(argument_spec={}, supports_check_mode=True,) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # according to Sat>IP Specification 1.2.2, p. 20 # a client should send three requests within 100 ms with a ttl of 2 sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) sock.settimeout(SSDP_MX + 0.5) for _ in range(3): sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT)) time.sleep(0.03) try: response = sock.recv(1000) if response and "SERVER:" in response: got_response = True else: raise ValueError('No satip server detected') except (socket.timeout, ValueError): got_response = False module.exit_json(changed=False, ansible_facts={'satip_detected': got_response}) if __name__ == '__main__': main() #+END_SRC * Handlers #+BEGIN_SRC yaml :tangle handlers/main.yml :mkdirp yes - name: Restart Samba systemd: name: smbd.service state: restarted enabled: yes #masked: no register: samba_reload - name: Restart NFS Kernel Server systemd: name: nfs-server.service state: restarted enabled: yes #masked: no register: nfs_reload - name: Restart VDR systemd: name: vdr.service state: restarted enabled: yes register: vdr_restart #+END_SRC