Merge branch 'refactoring'

This commit is contained in:
Alexander Grothe 2017-11-22 12:04:13 +01:00
commit 6b130a3df3
26 changed files with 1322 additions and 729 deletions

File diff suppressed because it is too large Load Diff

View File

@ -148,7 +148,7 @@ add-apt-repository -y ppa:ansible/ansible
# update packages # update packages
apt-get update apt-get update
# install required packages # install required packages
apt-get -y install ansible apt-get -y install --no-install-recommends ansible
# TODO: run ansible on local host # TODO: run ansible on local host
ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local --tags=install ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local --tags=install
@ -166,8 +166,10 @@ The ~yavdr07.yml~ playbook sets up a fully-featured yaVDR installation:
become: true become: true
roles: roles:
- yavdr-common # install and configure the basic system - yavdr-common # install and configure the basic system
- collect-facts # query system facts
- autoinstall-ubuntu-drivers # use ubuntu-drivers to install proprietary dirvers - autoinstall-ubuntu-drivers # use ubuntu-drivers to install proprietary dirvers
# (e.g. nvidia, virtualbox) # (e.g. nvidia, virtualbox)
- autoinstall-virtualbox-guest
# - nvidia-387 # install very recent nvidia-387 from ppa:graphics-drivers/ppa # - nvidia-387 # install very recent nvidia-387 from ppa:graphics-drivers/ppa
- vdr # install vdr and related packages - vdr # install vdr and related packages
- yavdr-network # enable network client capabilities - yavdr-network # enable network client capabilities
@ -184,9 +186,11 @@ The ~yavdr07.yml~ playbook sets up a fully-featured yaVDR installation:
- autoinstall-hauppauge-pvr # install vdr-plugin-pvrinput if a matching card is found - autoinstall-hauppauge-pvr # install vdr-plugin-pvrinput if a matching card is found
- autoinstall-dvbsddevice # install vdr-plugin-dvbsddevice if a matching card is detected - autoinstall-dvbsddevice # install vdr-plugin-dvbsddevice if a matching card is detected
- autoinstall-hardware-irmp # install yavdr-hardware-irmp if a matching usb device is detected - autoinstall-hardware-irmp # install yavdr-hardware-irmp if a matching usb device is detected
- autoinstall-dvbsky-firmware # download an install required firmware files for dvbsky cards
- kodi - kodi
- dvd # set up packages and a udev rule to allow kodi and other players - dvd # set up packages and a udev rule to allow kodi and other players
# to play and eject optical media # to play and eject optical media
- wakeup # set up wakeup methods for rtc etc.
- grub-config # configure grub - grub-config # configure grub
tags: tags:
- always - always
@ -206,6 +210,7 @@ For a headless server installation ~yavdr07-headless.yml~ is a good choice
become: true become: true
roles: roles:
- yavdr-common - yavdr-common
- collect-facts # query system facts
- vdr - vdr
- yavdr-network - yavdr-network
- samba-server - samba-server
@ -213,6 +218,7 @@ For a headless server installation ~yavdr07-headless.yml~ is a good choice
- nfs-server - nfs-server
- grub-config - grub-config
- autoinstall-satip - autoinstall-satip
- wakeup
tags: tags:
- always - always
handlers: handlers:
@ -300,7 +306,6 @@ extra_packages:
- bpython3 - bpython3
- htop - htop
- tree - tree
- vdr-addon-acpiwakeup
- vim - vim
- w-scan - w-scan
#+END_SRC #+END_SRC
@ -309,6 +314,7 @@ extra_packages:
frontend: vdr frontend: vdr
#system: #system:
# shutdown: poweroff # shutdown: poweroff
wakeup_method: acpiwakeup
grub: grub:
timeout: 0 timeout: 0
boot_options: quiet nosplash boot_options: quiet nosplash
@ -412,9 +418,20 @@ vdr:
*** tasks *** tasks
yavdr-common executes the following tasks: yavdr-common executes the following tasks:
**** main.yml **** main.yml
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes :padline no
---
# file: roles/yavdr-common/tasks/main.yml
- name: basic installation
block:
- import_tasks: configure_apt.yml
- import_tasks: configure_system.yml
- import_tasks: create_directories.yml
tags: [install]
#+END_SRC
***** Disable default installation of recommended packages ***** Disable default installation of recommended packages
This task prevents apt to automatically install all recommended dependencies for 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 :padline no #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_apt.yml :mkdirp yes :padline no
--- ---
- name: apt | prevent automatic installation of recommended packages - name: apt | prevent automatic installation of recommended packages
@ -423,8 +440,22 @@ yavdr-common executes the following tasks:
dest: /etc/apt/apt.conf.d/90norecommends dest: /etc/apt/apt.conf.d/90norecommends
#+END_SRC #+END_SRC
***** Set up package repositories
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_apt.yml :mkdirp yes
- name: add PPAs
apt_repository:
repo: '{{ item }}'
state: present
update_cache: yes
with_items: '{{ repositories }}'
- name: run apt-get dist-upgrade
apt:
upgrade: dist
update_cache: yes
#+END_SRC
***** Use bash instead of dash ***** Use bash instead of dash
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_system.yml :mkdirp yes
- name: use bash instead of dash - name: use bash instead of dash
shell: | shell: |
echo "set dash/sh false" | debconf-communicate echo "set dash/sh false" | debconf-communicate
@ -432,7 +463,7 @@ yavdr-common executes the following tasks:
#+END_SRC #+END_SRC
***** create user vdr ***** create user vdr
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :exports none :mkdirp yes #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_system.yml :exports none :mkdirp yes
- name: create vdr group - name: create vdr group
group: group:
gid: '{{ vdr.gid }}' gid: '{{ vdr.gid }}'
@ -451,7 +482,11 @@ yavdr-common executes the following tasks:
#+END_SRC #+END_SRC
***** Disable release-upgrade notifications ***** Disable release-upgrade notifications
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes ****** SOMEDAY move from lineinfile to template
:LOGBOOK:
- State "SOMEDAY" from "TODO" [2017-11-22 Mi 10:59]
:END:
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_system.yml :mkdirp yes
- name: disable release-upgrade notifications - name: disable release-upgrade notifications
lineinfile: lineinfile:
dest: /etc/update-manager/release-upgrades dest: /etc/update-manager/release-upgrades
@ -459,23 +494,15 @@ yavdr-common executes the following tasks:
state: present state: present
regexp: '^(Prompt=).*$' regexp: '^(Prompt=).*$'
line: '\1never' line: '\1never'
#+END_SRC ignore_errors: yes
***** Set up package repositories with_first_found:
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes - files:
- name: add PPAs - /etc/update-manager/release-upgrades
apt_repository: skip: true
repo: '{{ item }}'
state: present
update_cache: yes
with_items: '{{ repositories }}'
- name: run apt-get dist-upgrade #+END_SRC
apt:
upgrade: dist
update_cache: yes
#+END_SRC
***** Install essential packages ***** Install essential packages
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_system.yml :mkdirp yes
- name: apt | install basic packages - name: apt | install basic packages
apt: apt:
name: '{{ item }}' name: '{{ item }}'
@ -503,7 +530,7 @@ yavdr-common executes the following tasks:
#+END_SRC #+END_SRC
***** Install additional packages (user defined) ***** Install additional packages (user defined)
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/configure_system.yml
- name: apt | install extra packages - name: apt | install extra packages
apt: apt:
name: '{{ item }}' name: '{{ item }}'
@ -512,26 +539,14 @@ yavdr-common executes the following tasks:
with_items: with_items:
'{{ extra_packages }}' '{{ extra_packages }}'
#+END_SRC #+END_SRC
***** Gather facts with custom modules ***** create directories
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :mkdirp yes #+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/create_directories.yml :exports none :mkdirp yes
- name: get information about usb and pci hardware and loaded kernel modules - name: ensure /etc/yavdr exists
hardware_facts: file:
usb: True path: /etc/yavdr
pci: True state: directory
modules: True mode: 0755
gpus: True
- debug:
var: '{{ item }}'
verbosity: 1
with_items:
- usb
- pci
- gpus
- modules
#+END_SRC
***** create media directories
#+BEGIN_SRC yaml :tangle roles/yavdr-common/tasks/main.yml :exports none :mkdirp yes
- name: create media directories - name: create media directories
file: file:
dest: '{{ item.value }}' dest: '{{ item.value }}'
@ -548,6 +563,32 @@ yavdr-common executes the following tasks:
APT::Install-Recommends "0"; APT::Install-Recommends "0";
APT::Install-Suggests "0"; APT::Install-Suggests "0";
#+END_SRC #+END_SRC
** collect facts about the system with custom modules
*** tasks
***** main.yml
#+BEGIN_SRC yaml :tangle roles/collect-facts/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
acpi_power_modes: True
- debug:
var: '{{ item }}'
verbosity: 1
with_items:
- usb
- pci
- gpus
- modules
- acpi_power_modes
- nvidia_detected
- intel_detected
- amd_detected
- virtualbox_detected
#+END_SRC
** vdr ** vdr
*** tasks *** tasks
**** install the basic vdr packages **** install the basic vdr packages
@ -1031,7 +1072,10 @@ In order to achive a clean shutdown of the session, ~x@t7.service~ is set as a d
*** TODO automatic X-server configuration :noexport: *** TODO automatic X-server configuration :noexport:
- [X] detect connected display - [X] detect connected display
- [X] read EDID from displays - [X] read EDID from displays
- [ ] create a xorg.conf for nvidia/intel/amd gpus create a xorg.conf for
- [X] nvidia
- [ ] intel
- [ ] amd gpus
**** HOLD Nvidia-GPUs:read EDID: **** HOLD Nvidia-GPUs:read EDID:
@ -1428,31 +1472,31 @@ b'\xde\xad\xbe\xef'
dest: '{{ item }}' dest: '{{ item }}'
state: directory state: directory
with_items: with_items:
- /etc/systemd/system/x@.service.d/ - "/etc/systemd/system/x@.service.d/"
- /etc/systemd/system/vdr.service.d/ - "/etc/systemd/system/vdr.service.d/"
- '/etc/systemd/system/user@{{ vdr.uid }}.service.d/' - "/etc/systemd/system/user@{{ vdr.uid }}.service.d/"
- name: add dependency to X-server for vdr.service using a drop-in - name: systemd-drop-in | add dependency to X-server for vdr.service
template: template:
src: templates/vdr-xorg.conf src: templates/vdr-xorg.conf
dest: /etc/systemd/system/vdr.service.d/vdr-xorg.conf dest: /etc/systemd/system/vdr.service.d/vdr-xorg.conf
- name: start x@.service before xlogin@.service - name: systemd-drop-in | start x@.service before xlogin@.service
template: template:
src: templates/x@service.d/xlogin.conf.j2 src: templates/x@service.d/xlogin.conf.j2
dest: /etc/systemd/system/x@.service.d/xlogin.conf dest: /etc/systemd/system/x@.service.d/xlogin.conf
- name: load environment file for vdr.service - name: systemd-drop-in | load environment file for vdr.service
template: template:
src: templates/systemd/vdr-environ.j2 src: templates/systemd/vdr-environ.j2
dest: /etc/systemd/system/vdr.service.d/load-environ.conf dest: /etc/systemd/system/vdr.service.d/load-environ.conf
- name: user@{{ vdr.uid }}.service depends on x@vt7.service - name: systemd-drop-in | user@{{ vdr.uid }}.service depends on x@vt7.service
template: template:
src: templates/user@666.service.d/x-dependency.conf.j2 src: templates/user@666.service.d/x-dependency.conf.j2
dest: '/etc/systemd/system/user@{{ vdr.uid }}.service.d/x-dependency.conf' dest: '/etc/systemd/system/user@{{ vdr.uid }}.service.d/x-dependency.conf'
- name: start softhddevice detached and set audio to pulseaudio - name: vdr-config | start softhddevice detached and set audio to pulseaudio
lineinfile: lineinfile:
path: /etc/vdr/conf.avail/softhddevice.conf path: /etc/vdr/conf.avail/softhddevice.conf
line: '{{ item }}' line: '{{ item }}'
@ -1460,7 +1504,7 @@ b'\xde\xad\xbe\xef'
- '-D' - '-D'
# - '-a pulse' # do we need this with our existing asound.conf? # - '-a pulse' # do we need this with our existing asound.conf?
- name: set a login shell for the user vdr - name: add a login shell for the user vdr
user: user:
name: '{{ vdr.user }}' name: '{{ vdr.user }}'
shell: '/bin/bash' shell: '/bin/bash'
@ -1527,6 +1571,10 @@ b'\xde\xad\xbe\xef'
name: x@vt7.service name: x@vt7.service
state: stopped state: stopped
- name: "wait a little bit before starting x-verbose@vt7.service (needed?)"
wait_for:
timeout: 3
- name: "start x-verbose@.service" - name: "start x-verbose@.service"
systemd: systemd:
name: "x-verbose@vt7.service" name: "x-verbose@vt7.service"
@ -1556,14 +1604,24 @@ b'\xde\xad\xbe\xef'
enabled: false enabled: false
masked: true masked: true
- name: "wait a little bit, so X has some time to shut down (needed?)"
wait_for:
timeout: 3
# TODO: expand template for xorg.conf (or snippets) # TODO: expand template for xorg.conf (or snippets)
# with respect for the available graphics card driver # with respect for the available graphics card driver
# nvidia, noveau, intel, radeon # nvidia, noveau, intel, radeon
- name: create xorg.conf (for nvidia driver)
template: - name: nvidia related config
src: templates/xorg.conf.j2 block:
dest: /etc/X11/xorg.conf - name: create xorg.conf (for nvidia driver)
backup: yes template:
src: templates/xorg.conf.j2
dest: /etc/X11/xorg.conf
backup: yes
when:
- nvidia_detected
#+END_SRC #+END_SRC
#+BEGIN_SRC yaml :tangle roles/yavdr-xorg/tasks/desktop-session.yml :mkdirp yes :padline no #+BEGIN_SRC yaml :tangle roles/yavdr-xorg/tasks/desktop-session.yml :mkdirp yes :padline no
@ -3131,19 +3189,47 @@ The tool ubuntu-drivers is used to install the matching driver version for nvidi
#+BEGIN_SRC yaml :tangle roles/autoinstall-ubuntu-drivers/tasks/main.yml :padline no #+BEGIN_SRC yaml :tangle roles/autoinstall-ubuntu-drivers/tasks/main.yml :padline no
--- ---
# file roles/autoinstall-ubuntu-drivers/tasks/main.yml # file roles/autoinstall-ubuntu-drivers/tasks/main.yml
- name: apt | install ubuntu-drivers-common
apt:
name: ubuntu-drivers-common
state: present
- name: ensure /etc/yavdr exists - name: autoinstall ubuntu-drivers-common
file: block:
path: /etc/yavdr - name: apt | install ubuntu-drivers-common
state: directory apt:
mode: 0755 name: ubuntu-drivers-common
state: present
- name: let ubuntu-drivers automatically install additional drivers - name: use ubuntu-drivers to install additional drivers automatically
command: ubuntu-drivers --package-list /etc/yavdr/autoinstalled autoinstall command: ubuntu-drivers --package-list /etc/yavdr/autoinstalled autoinstall
when:
- ansible_virtualization_type != "virtualbox"
- ansible_virtualization_role != "guest"
- ansible_distribution == "Ubuntu"
- ansible_distribution_version != "16.04" # ubuntu-drivers-common tries to autoinstall
# conflicting packages for virtualbox :(
#+END_SRC
** autoinstall-virtualbox-guest
This role installs the guest additions for virtualbox guests on Ubuntu 16.04
#+BEGIN_SRC yaml :tangle roles/autoinstall-virtualbox-guest/tasks/main.yml :padline no
---
# file roles/autoinstall-virtualbox-guest/tasks/main.yml
- name: install virtualbox guest additions
block:
- name: install packages
apt:
state: present
name: '{{ item }}'
with_items:
- virtualbox-guest-dkms
- virtualbox-guest-x11
- dkms
# TODO: set xineliboutput as frontend
when:
- ansible_virtualization_type == "virtualbox"
- ansible_virtualization_role == "guest"
- ansible_distribution == "Ubuntu"
- ansible_distribution_version == "16.04"
#+END_SRC #+END_SRC
** autoinstall-satip ** autoinstall-satip
If a Sat>IP Server responds to a discovery request, the package vdr-plugin-satip is installed. If a Sat>IP Server responds to a discovery request, the package vdr-plugin-satip is installed.
@ -3162,6 +3248,7 @@ If a Sat>IP Server responds to a discovery request, the package vdr-plugin-satip
- name: apt | install vdr-plugin-satip if a Sat>IP server has been detected - name: apt | install vdr-plugin-satip if a Sat>IP server has been detected
apt: apt:
name: vdr-plugin-satip name: vdr-plugin-satip
state: present
when: satip_devices when: satip_devices
notify: [ 'Restart VDR' ] notify: [ 'Restart VDR' ]
#+END_SRC #+END_SRC
@ -3225,6 +3312,11 @@ If a Sat>IP Server responds to a discovery request, the package vdr-plugin-satip
when: '"0070:4000" in pci or "4444:0016" in pci' when: '"0070:4000" in pci or "4444:0016" in pci'
notify: [ 'Restart VDR' ] notify: [ 'Restart VDR' ]
#+END_SRC #+END_SRC
** autoinstall-dvbsky-firmware
*** defaults
#+INCLUDE: "roles/autoinstall-dvbsky-firmware/defaults/main.yml" src yaml
*** tasks
#+INCLUDE: "roles/autoinstall-dvbsky-firmware/tasks/main.yml" src yaml
** TODO autoinstall-dvbhddevice ** TODO autoinstall-dvbhddevice
Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware sollte in yavdr-firmware stecken Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware sollte in yavdr-firmware stecken
*** tasks *** tasks
@ -3262,6 +3354,7 @@ Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware soll
- name: apt | install yavdr-hardware-irmp if connected - name: apt | install yavdr-hardware-irmp if connected
apt: apt:
name: yavdr-hardware-irmp name: yavdr-hardware-irmp
state: present
when: '"1209:4444" in usb' when: '"1209:4444" in usb'
#+END_SRC #+END_SRC
@ -3538,6 +3631,51 @@ system:
mode: mode:
- "1280x720_60" - "1280x720_60"
#+END_SRC #+END_SRC
** wakeup
*** defaults
#+BEGIN_SRC yaml :tangle roles/wakeup/defaults/main.yml :padline no
---
# file roles/wakeup/defaults/main.yml
wakeup_method: "acpiwakeup"
#+END_SRC
*** tasks
#+BEGIN_SRC yaml :tangle roles/wakeup/tasks/main.yml :padline no
---
# file roles/wakeup/tasks/main.yml
- name: install and configure vdr-addon-acpiwakeup
apt:
name: vdr-addon-acpiwakeup
state: present
when: wakeup_method == "acpiwakeup"
- name: expand template for /etc/vdr/vdr-addon-acpiwakeup.conf
template:
src: templates/vdr-addon-acpiwakeup.conf.j2
dest: /etc/vdr/vdr-addon-acpiwakeup.conf
#+END_SRC
*** templates
#+BEGIN_SRC jinja2 :tangle roles/wakeup/templates/vdr-addon-acpiwakeup.conf.j2 :padline no
{{ ansible_managed_file | comment }}
# Activate/deactivate ACPIWakeup with yes/no:
ACPI_ENABLED="{% if wakeup_method == 'acpiwakeup' %}yes{% else %}no{% endif %}"
# How many minutes should the machine wake up before the timer starts:
ACPI_START_AHEAD=5
# If you want your VDR machine to wakeup in regular intervals (i.e. for
# updating EPG data), specify the days of the week and the wakeup time.
#
# Days of the week for regular wakeup (not set=Disabled, 1=Monday...7=Sunday)
# ACPI_REGULAR_DAYS="1 2 3 4 5 6 7"
# Wakeup time
#ACPI_REGULAR_TIME=01:00 # HH:MM
#+END_SRC
** grub-config ** grub-config
*** default variables *** default variables
#+BEGIN_SRC yaml :tangle roles/grub-config/defaults/main.yml :mkdirp yes :padline no #+BEGIN_SRC yaml :tangle roles/grub-config/defaults/main.yml :mkdirp yes :padline no
@ -3635,6 +3773,12 @@ DOCUMENTATION = '''
default: True default: True
description: description:
- return a list of devices of the pci gpu class (0x030000) - return a list of devices of the pci gpu class (0x030000)
acpi_power_modes:
required: False
default: True
description:
- return a list of supported acpi power saving modes
notes: notes:
- requres python-pyusb and python-kmodpy - requres python-pyusb and python-kmodpy
requirements: [ ] requirements: [ ]
@ -3647,13 +3791,14 @@ EXAMPLES = '''
usb: True usb: True
pci: True pci: True
modules: True modules: True
acpi_power_modes: True
- debug: - debug:
var: usb var: usb
- debug - debug:
var: pci var: pci
- debug - debug:
var: modules var: modules
- debug - debug:
var: gpus var: gpus
''' '''
@ -3701,11 +3846,21 @@ def format_gpu_device_list(iterator):
"VendorID": d.idVendor, "ProductID": d.idProduct} "VendorID": d.idVendor, "ProductID": d.idProduct}
return [entry for entry in get_entries(iterator)] return [entry for entry in get_entries(iterator)]
def list_acpi_power_modes():
acpi_power_modes = []
try:
with open('/sys/power/state') as f:
acpi_power_modes = [l for l in f.readline().split()]
except IOError:
pass
return acpi_power_modes
arg_specs = { arg_specs = {
'usb': dict(default=True, type='bool', required=False), 'usb': dict(default=True, type='bool', required=False),
'pci': dict(default=True, type='bool', required=False), 'pci': dict(default=True, type='bool', required=False),
'modules': dict(default=True, type='bool', required=False), 'modules': dict(default=True, type='bool', required=False),
'gpus': dict(default=True, type='bool', required=False), 'gpus': dict(default=True, type='bool', required=False),
'acpi_power_modes': dict(default=True, type='bool', required=False),
} }
@ -3715,24 +3870,42 @@ def main():
collect_pci = module.params['pci'] collect_pci = module.params['pci']
collect_modules = module.params['modules'] collect_modules = module.params['modules']
collect_gpus = module.params['gpus'] collect_gpus = module.params['gpus']
collect_acpi_power_modes = module.params['acpi_power_modes']
usb_devices = []
pci_devices = []
modules = []
gpus = []
nvidia_detected = False
intel_detected = False
amd_detected = False
virtualbox_detected = False
acpi_power_modes = []
if collect_usb: if collect_usb:
usb_devices = format_device_list(usb.core.find(find_all=True)) usb_devices = format_device_list(usb.core.find(find_all=True))
else:
usb_device = []
if collect_pci: if collect_pci:
pci_devices = format_device_list(get_pci_devices()) pci_devices = format_device_list(get_pci_devices())
else:
pci_devices = []
if collect_modules: if collect_modules:
k = kmodpy.Kmod() k = kmodpy.Kmod()
modules = [m[0] for m in k.loaded()] modules = [m[0] for m in k.loaded()]
else:
modules = []
if collect_gpus: if collect_gpus:
gpus = format_gpu_device_list(get_pci_devices()) gpus = format_gpu_device_list(get_pci_devices())
else: nvidia_detected = any((True for gpu in gpus if gpu['VendorName'] == 'nvidia'))
gpus = [] intel_detected = any((True for gpu in gpus if gpu['VendorName'] == 'intel'))
data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus} amd_detected = any((True for gpu in gpus if gpu['VendorName'] == 'amd'))
virtualbox_detected = any((True for gpu in gpus if gpu['VendorName'] == 'virtualbox'))
if collect_acpi_power_modes:
acpi_power_modes = list_acpi_power_modes()
data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus,
'acpi_power_modes': acpi_power_modes, 'nvidia_detected': nvidia_detected,
'intel_detected': intel_detected, 'amd_detected': amd_detected,
'virtualbox_detected': virtualbox_detected}
module.exit_json(changed=False, ansible_facts=data, msg=data) module.exit_json(changed=False, ansible_facts=data, msg=data)
@ -4061,6 +4234,9 @@ def collect_nvidia_data():
universal_newlines=True) universal_newlines=True)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
except OSError:
# nvidia-smi is not installed
pass
else: else:
for row in csv.DictReader(data.splitlines(), delimiter=',', skipinitialspace=True): for row in csv.DictReader(data.splitlines(), delimiter=',', skipinitialspace=True):
name = row['name'] name = row['name']
@ -4135,6 +4311,9 @@ if __name__ == '__main__':
#+BEGIN_SRC yaml :tangle handlers/main.yml :mkdirp yes #+BEGIN_SRC yaml :tangle handlers/main.yml :mkdirp yes
- name: Reconfigure unattended upgrades with dpkg - name: Reconfigure unattended upgrades with dpkg
command: '/usr/sbin/dpkg-reconfigure --frontend noninteractive unattended-upgrades' command: '/usr/sbin/dpkg-reconfigure --frontend noninteractive unattended-upgrades'
- name: Trigger Udev
command: 'udevadm trigger '
- name: Restart Samba - name: Restart Samba
systemd: systemd:

View File

@ -50,12 +50,12 @@ extra_packages:
- bpython3 - bpython3
- htop - htop
- tree - tree
- vdr-addon-acpiwakeup
- vim - vim
- w-scan - w-scan
frontend: vdr frontend: vdr
#system: #system:
# shutdown: poweroff # shutdown: poweroff
wakeup_method: acpiwakeup
grub: grub:
timeout: 0 timeout: 0
boot_options: quiet nosplash boot_options: quiet nosplash

View File

@ -1,5 +1,8 @@
- name: Reconfigure unattended upgrades with dpkg - name: Reconfigure unattended upgrades with dpkg
command: '/usr/sbin/dpkg-reconfigure --frontend noninteractive unattended-upgrades' command: '/usr/sbin/dpkg-reconfigure --frontend noninteractive unattended-upgrades'
- name: Trigger Udev
command: 'udevadm trigger '
- name: Restart Samba - name: Restart Samba
systemd: systemd:

View File

@ -10,7 +10,7 @@ add-apt-repository -y ppa:ansible/ansible
# update packages # update packages
apt-get update apt-get update
# install required packages # install required packages
apt-get -y install ansible apt-get -y install --no-install-recommends ansible
# TODO: run ansible on local host # TODO: run ansible on local host
ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local --tags=install ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local --tags=install

View File

@ -31,6 +31,12 @@ DOCUMENTATION = '''
default: True default: True
description: description:
- return a list of devices of the pci gpu class (0x030000) - return a list of devices of the pci gpu class (0x030000)
acpi_power_modes:
required: False
default: True
description:
- return a list of supported acpi power saving modes
notes: notes:
- requres python-pyusb and python-kmodpy - requres python-pyusb and python-kmodpy
requirements: [ ] requirements: [ ]
@ -43,13 +49,14 @@ EXAMPLES = '''
usb: True usb: True
pci: True pci: True
modules: True modules: True
acpi_power_modes: True
- debug: - debug:
var: usb var: usb
- debug - debug:
var: pci var: pci
- debug - debug:
var: modules var: modules
- debug - debug:
var: gpus var: gpus
''' '''
@ -97,11 +104,21 @@ def format_gpu_device_list(iterator):
"VendorID": d.idVendor, "ProductID": d.idProduct} "VendorID": d.idVendor, "ProductID": d.idProduct}
return [entry for entry in get_entries(iterator)] return [entry for entry in get_entries(iterator)]
def list_acpi_power_modes():
acpi_power_modes = []
try:
with open('/sys/power/state') as f:
acpi_power_modes = [l for l in f.readline().split()]
except IOError:
pass
return acpi_power_modes
arg_specs = { arg_specs = {
'usb': dict(default=True, type='bool', required=False), 'usb': dict(default=True, type='bool', required=False),
'pci': dict(default=True, type='bool', required=False), 'pci': dict(default=True, type='bool', required=False),
'modules': dict(default=True, type='bool', required=False), 'modules': dict(default=True, type='bool', required=False),
'gpus': dict(default=True, type='bool', required=False), 'gpus': dict(default=True, type='bool', required=False),
'acpi_power_modes': dict(default=True, type='bool', required=False),
} }
@ -111,24 +128,42 @@ def main():
collect_pci = module.params['pci'] collect_pci = module.params['pci']
collect_modules = module.params['modules'] collect_modules = module.params['modules']
collect_gpus = module.params['gpus'] collect_gpus = module.params['gpus']
collect_acpi_power_modes = module.params['acpi_power_modes']
usb_devices = []
pci_devices = []
modules = []
gpus = []
nvidia_detected = False
intel_detected = False
amd_detected = False
virtualbox_detected = False
acpi_power_modes = []
if collect_usb: if collect_usb:
usb_devices = format_device_list(usb.core.find(find_all=True)) usb_devices = format_device_list(usb.core.find(find_all=True))
else:
usb_device = []
if collect_pci: if collect_pci:
pci_devices = format_device_list(get_pci_devices()) pci_devices = format_device_list(get_pci_devices())
else:
pci_devices = []
if collect_modules: if collect_modules:
k = kmodpy.Kmod() k = kmodpy.Kmod()
modules = [m[0] for m in k.loaded()] modules = [m[0] for m in k.loaded()]
else:
modules = []
if collect_gpus: if collect_gpus:
gpus = format_gpu_device_list(get_pci_devices()) gpus = format_gpu_device_list(get_pci_devices())
else: nvidia_detected = any((True for gpu in gpus if gpu['VendorName'] == 'nvidia'))
gpus = [] intel_detected = any((True for gpu in gpus if gpu['VendorName'] == 'intel'))
data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus} amd_detected = any((True for gpu in gpus if gpu['VendorName'] == 'amd'))
virtualbox_detected = any((True for gpu in gpus if gpu['VendorName'] == 'virtualbox'))
if collect_acpi_power_modes:
acpi_power_modes = list_acpi_power_modes()
data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus,
'acpi_power_modes': acpi_power_modes, 'nvidia_detected': nvidia_detected,
'intel_detected': intel_detected, 'amd_detected': amd_detected,
'virtualbox_detected': virtualbox_detected}
module.exit_json(changed=False, ansible_facts=data, msg=data) module.exit_json(changed=False, ansible_facts=data, msg=data)

View File

@ -197,6 +197,9 @@ def collect_nvidia_data():
universal_newlines=True) universal_newlines=True)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
except OSError:
# nvidia-smi is not installed
pass
else: else:
for row in csv.DictReader(data.splitlines(), delimiter=',', skipinitialspace=True): for row in csv.DictReader(data.splitlines(), delimiter=',', skipinitialspace=True):
name = row['name'] name = row['name']

View File

@ -0,0 +1,3 @@
---
# file roles/autoinstall-dvbsky-firmware
dvbsky_firmware_files: []

View File

@ -0,0 +1,43 @@
---
# file roles/autoinstall-dvbsky-firmware/tasks/main.yml
- name: determine needed firmware files by device ids
block:
- name: add firmware for DVBSky S952 V3 to variable dvbsky_firmware_files if a card has been detected
set_fact:
dvbsky_firmware_files: "{{dvbsky_firmware_files}} + ['dvb-demod-m88rs6000.fw']"
when:
- '"1ade:3038" in pci'
- ansible_distribution_version >= '15.04' #driver only included since Kernel 3.19
when:
- not dvbsky_firmware_files
- name: Download firmware for DVBSky cards and copy required files to /lib/firmware
block:
# download and extract firmware
- unarchive:
src: http://www.dvbsky.net/download/linux/dvbsky-firmware.tar.gz
dest: /tmp/
remote_src: yes
# copy firmware file
- copy:
src: "/tmp/dvbsky-firmware/{{ item }}"
dest: /lib/firmware/
owner: root
group: root
mode: 0644
with_items: '{{ dvbsky_firmware_files }}'
notify: ['Trigger Udev']
# Remove temporary files
- file:
path: /tmp/dvbsky-firmware
state: absent
when:
- dvbsky_firmware_files is defined
- dvbsky_firmware_files
tags:
- install
- autodetect
- dvbsky

View File

@ -1,3 +1,3 @@
--- ---
dependencies: dependencies:
- { role: yavdr-common } - { role: collect-facts }

View File

@ -4,4 +4,5 @@
- name: apt | install yavdr-hardware-irmp if connected - name: apt | install yavdr-hardware-irmp if connected
apt: apt:
name: yavdr-hardware-irmp name: yavdr-hardware-irmp
state: present
when: '"1209:4444" in usb' when: '"1209:4444" in usb'

View File

@ -11,5 +11,6 @@
- name: apt | install vdr-plugin-satip if a Sat>IP server has been detected - name: apt | install vdr-plugin-satip if a Sat>IP server has been detected
apt: apt:
name: vdr-plugin-satip name: vdr-plugin-satip
state: present
when: satip_devices when: satip_devices
notify: [ 'Restart VDR' ] notify: [ 'Restart VDR' ]

View File

@ -1,15 +1,18 @@
--- ---
# file roles/autoinstall-ubuntu-drivers/tasks/main.yml # file roles/autoinstall-ubuntu-drivers/tasks/main.yml
- name: apt | install ubuntu-drivers-common
apt:
name: ubuntu-drivers-common
state: present
- name: ensure /etc/yavdr exists - name: autoinstall ubuntu-drivers-common
file: block:
path: /etc/yavdr - name: apt | install ubuntu-drivers-common
state: directory apt:
mode: 0755 name: ubuntu-drivers-common
state: present
- name: let ubuntu-drivers automatically install additional drivers - name: use ubuntu-drivers to install additional drivers automatically
command: ubuntu-drivers --package-list /etc/yavdr/autoinstalled autoinstall command: ubuntu-drivers --package-list /etc/yavdr/autoinstalled autoinstall
when:
- ansible_virtualization_type != "virtualbox"
- ansible_virtualization_role != "guest"
- ansible_distribution == "Ubuntu"
- ansible_distribution_version != "16.04" # ubuntu-drivers-common tries to autoinstall
# conflicting packages for virtualbox :(

View File

@ -0,0 +1,20 @@
---
# file roles/autoinstall-virtualbox-guest/tasks/main.yml
- name: install virtualbox guest additions
block:
- name: install packages
apt:
state: present
name: '{{ item }}'
with_items:
- virtualbox-guest-dkms
- virtualbox-guest-x11
- dkms
# TODO: set xineliboutput as frontend
when:
- ansible_virtualization_type == "virtualbox"
- ansible_virtualization_role == "guest"
- ansible_distribution == "Ubuntu"
- ansible_distribution_version == "16.04"

View File

@ -0,0 +1,21 @@
- name: get information about usb and pci hardware and loaded kernel modules
hardware_facts:
usb: True
pci: True
modules: True
gpus: True
acpi_power_modes: True
- debug:
var: '{{ item }}'
verbosity: 1
with_items:
- usb
- pci
- gpus
- modules
- acpi_power_modes
- nvidia_detected
- intel_detected
- amd_detected
- virtualbox_detected

View File

@ -0,0 +1,3 @@
---
# file roles/wakeup/defaults/main.yml
wakeup_method: "acpiwakeup"

View File

@ -0,0 +1,13 @@
---
# file roles/wakeup/tasks/main.yml
- name: install and configure vdr-addon-acpiwakeup
apt:
name: vdr-addon-acpiwakeup
state: present
when: wakeup_method == "acpiwakeup"
- name: expand template for /etc/vdr/vdr-addon-acpiwakeup.conf
template:
src: templates/vdr-addon-acpiwakeup.conf.j2
dest: /etc/vdr/vdr-addon-acpiwakeup.conf

View File

@ -0,0 +1,16 @@
{{ ansible_managed_file | comment }}
# Activate/deactivate ACPIWakeup with yes/no:
ACPI_ENABLED="{% if wakeup_method == 'acpiwakeup' %}yes{% else %}no{% endif %}"
# How many minutes should the machine wake up before the timer starts:
ACPI_START_AHEAD=5
# If you want your VDR machine to wakeup in regular intervals (i.e. for
# updating EPG data), specify the days of the week and the wakeup time.
#
# Days of the week for regular wakeup (not set=Disabled, 1=Monday...7=Sunday)
# ACPI_REGULAR_DAYS="1 2 3 4 5 6 7"
# Wakeup time
#ACPI_REGULAR_TIME=01:00 # HH:MM

View File

@ -0,0 +1,17 @@
---
- name: apt | prevent automatic installation of recommended packages
template:
src: templates/90-norecommends.j2
dest: /etc/apt/apt.conf.d/90norecommends
- name: add PPAs
apt_repository:
repo: '{{ item }}'
state: present
update_cache: yes
with_items: '{{ repositories }}'
- name: run apt-get dist-upgrade
apt:
upgrade: dist
update_cache: yes

View File

@ -0,0 +1,62 @@
- name: use bash instead of dash
shell: |
echo "set dash/sh false" | debconf-communicate
dpkg-reconfigure -f noninteractive dash
- 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
- name: disable release-upgrade notifications
lineinfile:
dest: /etc/update-manager/release-upgrades
backrefs: yes
state: present
regexp: '^(Prompt=).*$'
line: '\1never'
ignore_errors: yes
with_first_found:
- files:
- /etc/update-manager/release-upgrades
skip: true
- name: apt | install basic packages
apt:
name: '{{ item }}'
state: present
install_recommends: no
with_items:
- anacron
- acl
- at
- bash-completion
#- biosdevname # caution: may change device names after a minimal installation!
- debconf-utils
- linux-firmware
- psmisc
- python-kmodpy
- python-requests
- python-usb
- python3-usb
- software-properties-common
- ssh
- wget
- wpasupplicant
- usbutils
- xfsprogs
- name: apt | install extra packages
apt:
name: '{{ item }}'
state: present
install_recommends: no
with_items:
'{{ extra_packages }}'

View File

@ -0,0 +1,14 @@
- name: ensure /etc/yavdr exists
file:
path: /etc/yavdr
state: directory
mode: 0755
- name: create media directories
file:
dest: '{{ item.value }}'
owner: '{{ vdr.user }}'
group: '{{ vdr.group }}'
state: directory
mode: '0777'
with_dict: '{{ media_dirs }}'

View File

@ -1,97 +1,9 @@
--- ---
# file: roles/yavdr-common/tasks/main.yml
- name: apt | prevent automatic installation of recommended packages - name: basic installation
template: block:
src: templates/90-norecommends.j2 - import_tasks: configure_apt.yml
dest: /etc/apt/apt.conf.d/90norecommends - import_tasks: configure_system.yml
- name: use bash instead of dash - import_tasks: create_directories.yml
shell: | tags: [install]
echo "set dash/sh false" | debconf-communicate
dpkg-reconfigure -f noninteractive dash
- 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
- name: disable release-upgrade notifications
lineinfile:
dest: /etc/update-manager/release-upgrades
backrefs: yes
state: present
regexp: '^(Prompt=).*$'
line: '\1never'
- name: add PPAs
apt_repository:
repo: '{{ item }}'
state: present
update_cache: yes
with_items: '{{ repositories }}'
- name: run apt-get dist-upgrade
apt:
upgrade: dist
update_cache: yes
- name: apt | install basic packages
apt:
name: '{{ item }}'
state: present
install_recommends: no
with_items:
- anacron
- acl
- at
- bash-completion
#- biosdevname # caution: may change device names after a minimal installation!
- debconf-utils
- linux-firmware
- psmisc
- python-kmodpy
- python-requests
- python-usb
- python3-usb
- software-properties-common
- ssh
- wget
- wpasupplicant
- usbutils
- xfsprogs
- name: apt | install extra packages
apt:
name: '{{ item }}'
state: present
install_recommends: no
with_items:
'{{ extra_packages }}'
- name: get information about usb and pci hardware and loaded kernel modules
hardware_facts:
usb: True
pci: True
modules: True
gpus: True
- debug:
var: '{{ item }}'
verbosity: 1
with_items:
- usb
- pci
- gpus
- modules
- name: create media directories
file:
dest: '{{ item.value }}'
owner: '{{ vdr.user }}'
group: '{{ vdr.group }}'
state: directory
mode: '0777'
with_dict: '{{ media_dirs }}'

View File

@ -28,6 +28,10 @@
name: x@vt7.service name: x@vt7.service
state: stopped state: stopped
- name: "wait a little bit before starting x-verbose@vt7.service (needed?)"
wait_for:
timeout: 3
- name: "start x-verbose@.service" - name: "start x-verbose@.service"
systemd: systemd:
name: "x-verbose@vt7.service" name: "x-verbose@vt7.service"
@ -57,11 +61,20 @@
enabled: false enabled: false
masked: true masked: true
- name: "wait a little bit, so X has some time to shut down (needed?)"
wait_for:
timeout: 3
# TODO: expand template for xorg.conf (or snippets) # TODO: expand template for xorg.conf (or snippets)
# with respect for the available graphics card driver # with respect for the available graphics card driver
# nvidia, noveau, intel, radeon # nvidia, noveau, intel, radeon
- name: create xorg.conf (for nvidia driver)
template: - name: nvidia related config
src: templates/xorg.conf.j2 block:
dest: /etc/X11/xorg.conf - name: create xorg.conf (for nvidia driver)
backup: yes template:
src: templates/xorg.conf.j2
dest: /etc/X11/xorg.conf
backup: yes
when:
- nvidia_detected

View File

@ -5,31 +5,31 @@
dest: '{{ item }}' dest: '{{ item }}'
state: directory state: directory
with_items: with_items:
- /etc/systemd/system/x@.service.d/ - "/etc/systemd/system/x@.service.d/"
- /etc/systemd/system/vdr.service.d/ - "/etc/systemd/system/vdr.service.d/"
- '/etc/systemd/system/user@{{ vdr.uid }}.service.d/' - "/etc/systemd/system/user@{{ vdr.uid }}.service.d/"
- name: add dependency to X-server for vdr.service using a drop-in - name: systemd-drop-in | add dependency to X-server for vdr.service
template: template:
src: templates/vdr-xorg.conf src: templates/vdr-xorg.conf
dest: /etc/systemd/system/vdr.service.d/vdr-xorg.conf dest: /etc/systemd/system/vdr.service.d/vdr-xorg.conf
- name: start x@.service before xlogin@.service - name: systemd-drop-in | start x@.service before xlogin@.service
template: template:
src: templates/x@service.d/xlogin.conf.j2 src: templates/x@service.d/xlogin.conf.j2
dest: /etc/systemd/system/x@.service.d/xlogin.conf dest: /etc/systemd/system/x@.service.d/xlogin.conf
- name: load environment file for vdr.service - name: systemd-drop-in | load environment file for vdr.service
template: template:
src: templates/systemd/vdr-environ.j2 src: templates/systemd/vdr-environ.j2
dest: /etc/systemd/system/vdr.service.d/load-environ.conf dest: /etc/systemd/system/vdr.service.d/load-environ.conf
- name: user@{{ vdr.uid }}.service depends on x@vt7.service - name: systemd-drop-in | user@{{ vdr.uid }}.service depends on x@vt7.service
template: template:
src: templates/user@666.service.d/x-dependency.conf.j2 src: templates/user@666.service.d/x-dependency.conf.j2
dest: '/etc/systemd/system/user@{{ vdr.uid }}.service.d/x-dependency.conf' dest: '/etc/systemd/system/user@{{ vdr.uid }}.service.d/x-dependency.conf'
- name: start softhddevice detached and set audio to pulseaudio - name: vdr-config | start softhddevice detached and set audio to pulseaudio
lineinfile: lineinfile:
path: /etc/vdr/conf.avail/softhddevice.conf path: /etc/vdr/conf.avail/softhddevice.conf
line: '{{ item }}' line: '{{ item }}'
@ -37,7 +37,7 @@
- '-D' - '-D'
# - '-a pulse' # do we need this with our existing asound.conf? # - '-a pulse' # do we need this with our existing asound.conf?
- name: set a login shell for the user vdr - name: add a login shell for the user vdr
user: user:
name: '{{ vdr.user }}' name: '{{ vdr.user }}'
shell: '/bin/bash' shell: '/bin/bash'

View File

@ -7,6 +7,7 @@
become: true become: true
roles: roles:
- yavdr-common - yavdr-common
- collect-facts # query system facts
- vdr - vdr
- yavdr-network - yavdr-network
- samba-install - samba-install
@ -14,6 +15,7 @@
- nfs-server - nfs-server
- grub-config - grub-config
- autoinstall-satip - autoinstall-satip
- wakeup
tags: tags:
- always - always
handlers: handlers:

View File

@ -7,8 +7,10 @@
become: true become: true
roles: roles:
- yavdr-common # install and configure the basic system - yavdr-common # install and configure the basic system
- collect-facts # query system facts
- autoinstall-ubuntu-drivers # use ubuntu-drivers to install proprietary dirvers - autoinstall-ubuntu-drivers # use ubuntu-drivers to install proprietary dirvers
# (e.g. nvidia, virtualbox) # (e.g. nvidia, virtualbox)
- autoinstall-virtualbox-guest
# - nvidia-387 # install very recent nvidia-387 from ppa:graphics-drivers/ppa # - nvidia-387 # install very recent nvidia-387 from ppa:graphics-drivers/ppa
- vdr # install vdr and related packages - vdr # install vdr and related packages
- yavdr-network # enable network client capabilities - yavdr-network # enable network client capabilities
@ -25,9 +27,11 @@
- autoinstall-hauppauge-pvr # install vdr-plugin-pvrinput if a matching card is found - autoinstall-hauppauge-pvr # install vdr-plugin-pvrinput if a matching card is found
- autoinstall-dvbsddevice # install vdr-plugin-dvbsddevice if a matching card is detected - autoinstall-dvbsddevice # install vdr-plugin-dvbsddevice if a matching card is detected
- autoinstall-hardware-irmp # install yavdr-hardware-irmp if a matching usb device is detected - autoinstall-hardware-irmp # install yavdr-hardware-irmp if a matching usb device is detected
- autoinstall-dvbsky-firmware # download an install required firmware files for dvbsky cards
- kodi - kodi
- dvd # set up packages and a udev rule to allow kodi and other players - dvd # set up packages and a udev rule to allow kodi and other players
# to play and eject optical media # to play and eject optical media
- wakeup # set up wakeup methods for rtc etc.
- grub-config # configure grub - grub-config # configure grub
tags: tags:
- always - always