ODROID-HC2 and Ansible
Table of Contents
After installing Fedora 29 on my ODROID-HC2 nodes, I want to get an ansible user onto them so that my usual Ansible playbooks can configure them.
Overview of steps
- Ensure that both
python
andlibselinux-python
are installed on the ODROID - Ensure your ODROID-HC2 is in your inventory
- Set up variables as needed
- Ensure you can
ansible … -m ping …
- optional: Create an ansible user on the ODROID-HC2 by doing one of
- using a playbook that connects as user
root
- using shell commands
- using a playbook that connects as user
- optional: Run all future playbooks as the ansible user
If you’re interested, there’s also details on my own Ansible setup further below.
Prerequisites
- An OS supported by Ansible on your ODROID-HC2, I installed Fedora on mine
- Ability to log into the ODROID-HC2 via ssh as
root
using a ssh key
Should you be unable to ssh, then you will probablyt need a serial console to fix it. See installing Fedora 29 on my ODROID-HC2 for details on the serial console.
Prepare node for Ansible
Since the image Fedora-Minimal-armhfp-29-1.2
is lacking 2 packages needed for ansible
to control the node, install them manually.
On the ODROID, as root
dnf install python libselinux-python
NOTE: be patient with your first use of dnf
, it can take a few minutes.
This improves after dnf-makecache
ran once.
You can check the status of dnf-makecache.service
and system activity
on the ODROID, as root, by using
journalctl _SYSTEMD_UNIT=dnf-makecache.service
top -bn1 | head -n 10
Verify Ansible Connectivity
Verify that you can reach the ODROID with Ansible.
For now as user root
, as no ansible user in Fedora-Minimal-armhfp-29-1.2-sda.raw
On the Ansible control node
ansible odroid-hc2-00 -m ping -e ansible_user=root
Using -e ansible_user=root
ensures it takes highest variable precedence.
(thanks to jtanner for the doc pointer).
Unless of course you created a user for Ansible during your OS installation of the ODROID-HC2.
Then you drop the option, ansible odroid-hc2-00 -m ping
It should return this
odroid-hc2-00 | SUCCESS => {
"changed": false,
"ping": "pong"
}
If this fails, you will need to ssh -v
(with your key) to the ODROID as root
and debug why Ansible can not connect.
Configure your ODROID with Ansible
At this point, you can configure your ODROID-HC2 nodes’ Fedora with Ansible. Hopefully you wrote your playbooks and roles without hardcoding x86_64 ;-)
Notes:
- use the ssh privkey matching the pubkey you installed on the ODROID
- I recomend using
ssh-agent
if you Ansible from a shell or development environment - I recommend a credentials store if you use Ansible Tower.
- I recomend using
- as my installation instructions create only a root user,
initially start with an Ansible play that connects as root and sets up an ansible user.
- do not forget to set up password-less sudo.
You may want to continue reading to get an idea of the steps I perform.
my Ansible setup
Note that the below is just what I used while creating this post.
You probably want to use your own playbooks and roles now that you learned what needs doing.
This section mainly serves as a note to self.
group_vars
inventories/group_vars/ceph-housenet.yml
contains the following
---
user_owner: pcfe
ansible_user: ansible
common_timezone: Europe/Berlin
sample host_vars
inventories/host_vars/odroid-hc2-00.yml
---
ansible_python_interpreter: /usr/bin/python3
network_connections:
- name: "Wired connection 1"
type: "ethernet"
interface_name: "eth0"
zone: "public"
state: up
ip:
dhcp4: false
auto6: false
gateway4: 192.168.50.254
dns: 192.168.50.248
dns_search: internal.pcfe.net
address: 192.168.50.160/24
ansible_python_interpreter
because I use the firewalld module in my module pcfe.check_mk
.
inventory
inventories/ceph-ODROID-cluster.ini
contains the following
#[softiron]
#overdrive-1000
[odroids]
odroid-hc2-00
odroid-hc2-01
odroid-hc2-02
odroid-hc2-03
odroid-hc2-04
odroid-hc2-05
odroid-hc2-06
#odroid-hc2-[00:06]
[ceph_x86_nodes]
ceph-ansible
ceph-dashboard
ceph-rgw
ceph-mds-01
ceph-mds-02
ceph-mon-01
ceph-mon-02
ceph-mon-03
#altespielbuechse
[ceph_arm_nodes:children]
odroids
#softiron
[ceph_fedora_nodes]
odroid-hc2-[00:06]
[ceph_el_nodes]
#softiron
ceph-ansible
ceph-dashboard
ceph-rgw
ceph-mds-01
ceph-mds-02
ceph-mon-01
ceph-mon-02
ceph-mon-03
[ceph_housenet:children]
ceph_arm_nodes
ceph_x86_nodes
[ceph_housenet:vars]
ansible_user=ansible
[mons]
ceph-mon-01
ceph-mon-02
ceph-mon-03
# MGRs are typically collocated with MONs
[mgrs]
ceph-mon-01
ceph-mon-02
ceph-mon-03
[osds]
#overdrive-1000
f5-422-01
[osds:children]
odroids
# ceph-grafana should not live on an OSD node
[ceph-grafana]
ceph-dashboard
# RADOS Gateway running as a VM is supported
# https://access.redhat.com/articles/1548993
[rgws]
ceph-rgw
[mdss]
ceph-mds-01
ceph-mds-02
#[clients]
#t7910
#karhu
#openshift-master
#openshift-node-01
#openshift-router
My Initial Setup Playbook
My Playbook arm-fedora-initial-setup.yml
uses the following private roles
pcfe.user_owner
is abused to create the ansible userpcfe.basic-security-setup
sets non-negotiable security settingspcfe.housenet
sets up timezone and the use of local package mirrors
It will also
- set up chrony
- apply all errata
- ensure the ansible user can sudo without a password
The play arm-fedora-initial-setup.yml
is as follows
# initially sets up my ARM based boxes
# you can run this after completing the steps at
# https://blog.pcfe.net/hugo/posts/2019-01-27-fedora-29-on-odroid-hc2/
#
# this also works for boxes installed with
# Fedora-Server-dvd-aarch64-29-1.2.iso
#
# this initial setup Playbook must connect as user root,
# after it ran we can connect as user ansible.
# since user_owner is set (in vars: below) to 'ansible',
# pcfe.user_owner creates the user 'ansible' and drops in ssh pubkeys
#
# this is for my ODROID-HC2 boxes and my OverDrive 1000
#
- hosts:
- odroids
- softiron
- f5-422-01
become: no
roles:
- pcfe.user_owner
- pcfe.basic_security_setup
- pcfe.housenet
vars:
ansible_user: root
user_owner: ansible
tasks:
# should set hostname to ansible_fqdn
# https://docs.ansible.com/ansible/latest/modules/hostname_module.html
# F31 RC no longer seet to set it...
# debug first though
# start by enabling time sync, while my ODROIDs do have the RTC battery add-on, yours might not.
# Plus it's nice to be able to wake up the boards from poweroff
# and have the correct time alredy before chrony-wait runs at boot
- name: "CHRONYD | ensure chrony-wait is enabled"
service:
name: chrony-wait
enabled: true
- name: "CHRONYD | ensure chronyd is enabled and running"
service:
name: chronyd
enabled: true
state: started
# enable persistent journal
# DAFUQ? re-ran on all odroids, it reported 'changed' instead of 'ok'?!?
- name: "JOURNAL | ensure persistent logging for the systemd journal is possible"
file:
path: /var/log/journal
state: directory
owner: root
group: systemd-journal
mode: 0755
# enable passwordless sudo for the created ansible user
- name: "SUDO | enable passwordless sudo for ansible user"
copy:
dest: /etc/sudoers.d/ansible
content: |
ansible ALL=NOPASSWD: ALL
owner: root
group: root
mode: 0440
# I do want all errata applied
- name: "DNF | ensure all updates are applied"
dnf:
update_cache: yes
name: '*'
state: latest
tags: apply_errata
Output of Initial Setup Playbook
So that you can get an idea of what the roles used do, the full log follows. Still, you most probably want to use your own playbooks and roles.
ansible-playbook -i ../inventories/ceph-ODROID-cluster.ini -l odroid-hc2-00 --skip-tags apply_errata arm-fedora-initial-setup.yml | tee ../../hugo-blog.pcfe.net/static/code/arm-fedora-initial-setup.log
(In this example, I skip applying errata in order to get this log output quicker)
PLAY [ceph-arm-nodes] *********************************************************************************************** TASK [Gathering Facts] ********************************************************************************************** ok: [odroid-hc2-00] TASK [pcfe.user_owner : USER OWNER | ensure group ansible exists] *************************************************** ok: [odroid-hc2-00] TASK [pcfe.user_owner : USER OWNER | ensure user ansible exists] **************************************************** ok: [odroid-hc2-00] TASK [pcfe.user_owner : USER OWNER | ensure authorized key for ansible exists] ************************************** ok: [odroid-hc2-00] TASK [pcfe.user_owner : USER OWNER | ensure authorized key for root exists] ***************************************** ok: [odroid-hc2-00] TASK [pcfe.basic-security-setup : BASIC SEC | ensure selinux is running with enforcing] ***************************** ok: [odroid-hc2-00] TASK [pcfe.basic-security-setup : BASIC SEC | ensure ssh auth is via ssh-key only] ********************************** ok: [odroid-hc2-00] TASK [pcfe.housenet : TIMEZONE | ensure timezone is Europe/Berlin] ************************************************** ok: [odroid-hc2-00] TASK [pcfe.housenet : YUM | ensure repo CentOS-Updates-HouseNet is enabled if on CentOS >= 7.0] ********************* skipping: [odroid-hc2-00] TASK [pcfe.housenet : YUM | ensure updates repo is disabled if on CentOS >= 7.0] ************************************ skipping: [odroid-hc2-00] TASK [pcfe.housenet : YUM | ensure all security updates are applied if on CentOS >= 7.0] **************************** skipping: [odroid-hc2-00] TASK [pcfe.housenet : DNF | ensure repo fedora-updates-housenet is available if on Fedora >= 28] ******************** ok: [odroid-hc2-00] TASK [pcfe.housenet : DNF | ensure updates repo is disabled if on Fedora >= 28] ************************************* ok: [odroid-hc2-00] TASK [pcfe.housenet : DNF | ensure repo fedora-everything-housenet is enabled if on Fedora >= 28] ******************* ok: [odroid-hc2-00] TASK [pcfe.housenet : DNF | ensure fedora repo is disabled if on Fedora >= 28] ************************************** ok: [odroid-hc2-00] TASK [CHRONYD | ensure chrony-wait is enabled] ********************************************************************** ok: [odroid-hc2-00] TASK [CHRONYD | ensure chronyd is enabled and running] ************************************************************** ok: [odroid-hc2-00] TASK [JOURNAL | ensure persistent logging for the systemd journal is possible] ************************************** ok: [odroid-hc2-00] TASK [SUDO | enable passwordless sudo for ansible user] ************************************************************* ok: [odroid-hc2-00] PLAY RECAP ********************************************************************************************************** odroid-hc2-00 : ok=16 changed=0 unreachable=0 failed=0
My Site-Specific Setup Playbook
After I created the bare minimum with arm-fedora-initial-setup.yml
by running it once
(I’m not going to needlessly run the task DNF | ensure all updates are applied,
it takes a while), I have a bunch of local settings I like applied.
They are only shown here because I reference arm-fedora-initial-setup.yml
in another post.
My play odroid-general-setup.yml
uses these roles:
linux-system-roles.network
to set up static network configuration- new group name, update above
- host_vars containing static network info, idem
pcfe.basic-security-setup
sets non-negotiable settingspcfe.housenet
sets up timezone and the use of local package mirrorspcfe.user_owner
creates the user ‘pcfe’ (defined ingroup_vars/
) and copies over in my ssh pubkeypcfe.comfort
to set up some bits that make my shell use more comfortablepcfe.check_mk
sets up to host for monitoring with my local Check_MK instance
And the following tasks:
-
implements a dirty work-around until check-mk-agent ≥ 1.5.0 is available in Fedora
-
installs language packs for languages I speak.
- A nice side effect is that this stops dnf from complaining Failed to set locale, defaulting to C.
-
sets up the hardware watchdog.
- See Hardware Watchdog on Linux/Ubuntu in the ODROID Wiki for details.
-
sets up ODROID-HC2 tweaks
The play odroid-general-setup.yml
is as follows
# sets up a Fedora 29 ARM minimal install with site-specific settings
# to be run AFTER odroid-initial-setup.yml RAN ONCE at least
# this is for my ODROID-HC2 boxes
- hosts:
- odroids
become: yes
roles:
- linux-system-roles.network
- pcfe.basic_security_setup
- pcfe.user_owner
- pcfe.comfort
- pcfe.checkmk
# remove this Würgaround pre-task once 1.5.0 or later is available in Fedora repo
pre_tasks:
- name: "Ensure check-mk-agent-1.5.0 or later is installed, because earlier versions have trouble with thermal zone output"
dnf:
name: 'http://check-mk.internal.pcfe.net/HouseNet/check_mk/agents/check-mk-agent-1.6.0p5-1.noarch.rpm'
state: present
- name: "ensure /usr/share/check-mk-agent exists"
file:
path: /usr/share/check-mk-agent
state: directory
mode: 0755
- name: "symlink plugins and local from /usr/lib/check_mk_agent/ to /usr/share/check-mk-agent/"
file:
src: '/usr/lib/check_mk_agent/{{ item.src }}'
dest: '/usr/share/check-mk-agent/{{ item.dest }}'
state: link
with_items:
- { src: 'plugins', dest: 'plugins' }
- { src: 'local', dest: 'local' }
## That will only be necessary until "FEED-3415: linux smart plugin und JMicron USB nach SATA bridges" is fixed on Check_MK side
## 2020-01-09: well, the RPM from the check-mk server seems to lack the plugin, so enable anyway.
- name: "ensure smart plugin is installed"
template:
src: templates/ODROID-HC2/smart-for-check-mk.j2
dest: '/usr/lib/check_mk_agent/plugins/smart'
group: 'root'
mode: '0755'
owner: 'root'
tasks:
# # linux-system-roles.network sets static network config (from host_vars)
# # but I want the static hostname nailed down too
# # the below does not work though, try with ansible_fqdn instead
# - name: "set hostname"
# hostname:
# name: '{{ ansible_hostname }}.internal.pcfe.net'
# fix dnf's "Failed to set locale, defaulting to C" annoyance
- name: "PACKAGE | ensure my preferred langpacks are installed"
package:
name:
- langpacks-en
- langpacks-en_GB
- langpacks-de
- langpacks-fr
state: present
# enable watchdog based on information from https://wiki.odroid.com/odroid-xu4/application_note/software/linux_watchdog
# write watchdog kernel module config, this is needed to enable power cycle
# alternatively one could use the kernel boot parameters, but I personally prefer modprobe.d/
- name: "WATCHDOG | ensure kernel module s3c2410_wdt has correct options configured"
lineinfile:
path: /etc/modprobe.d/s3c2410_wdt.conf
create: true
regexp: '^options '
insertafter: '^#options'
line: 'options s3c2410_wdt tmr_margin=30 tmr_atboot=1 nowayout=0'
# while testing, configure both watchdog.service and systemd watchdog, but only use the latter for now.
- name: "PACKAGE | ensure watchdog package is installed"
package:
name: watchdog
state: present
- name: "WATCHDOG | ensure correct watchdog-device is used by watchdog.service"
lineinfile:
path: /etc/watchdog.conf
regexp: '^watchdog-device'
insertafter: '^#watchdog-device'
line: 'watchdog-device = /dev/watchdog'
# values above 32 seconds do not work, cannot set timeout 33 (errno = 22 = 'Invalid argument')
- name: "WATCHDOG | ensure timeout is set to 30 seconds for watchdog.service"
lineinfile:
path: /etc/watchdog.conf
regexp: '^watchdog-timeout'
insertafter: '^#watchdog-timeout'
line: 'watchdog-timeout = 30'
# testing in progress;
# Use systemd watchdog rather than watchdog.service
- name: "WATCHDOG | Ensure watchdog.service is disabled"
systemd:
name: watchdog.service
state: stopped
enabled: false
# configure systemd watchdog
# c.f. http://0pointer.de/blog/projects/watchdog.html
- name: "SYSTEMD | ensure systemd watchdog is enabled"
lineinfile:
path: /etc/systemd/system.conf
regexp: '^RuntimeWatchdogSec'
insertafter: 'EOF'
line: 'RuntimeWatchdogSec=30'
- name: "SYSTEMD | ensure systemd shutdown watchdog is enabled"
lineinfile:
path: /etc/systemd/system.conf
regexp: '^ShutdownWatchdogSec'
insertafter: 'EOF'
line: 'ShutdownWatchdogSec=30'
# install and enable rngd
- name: "PACKAGE | ensure rng-tools package is installed"
package:
name: rng-tools
state: present
- name: "RNGD | ensure rngd.service is enabled and started"
systemd:
name: rngd.service
state: started
enabled: true
# most tweaks taken from both
# https://forum.odroid.com/viewtopic.php?t=25424 and
# https://magazine.odroid.com/wp-content/uploads/ODROID-Magazine-201702.pdf#ODROID%20Magazine%20Issue%2038.indd:.314673:59549
- name: "ODROID-HC2 TWEAKS: ensure needed packages are installed"
package:
name:
- libcgroup-tools
- tuned
- perl-interpreter
- hdparm
- tar
- unzip
state: present
- name: "ODROID-HC2 TWEAKS: ensure odroid-cpu-control is available"
# from https://raw.githubusercontent.com/mad-ady/odroid-cpu-control/master/odroid-cpu-control
template:
src: templates/ODROID-HC2/odroid-cpu-control.j2
dest: /usr/local/bin/odroid-cpu-control
mode: '0755'
owner: root
group: root
- name: "ODROID-HC2 TWEAKS: ensure cpuset.service is available"
# from https://raw.githubusercontent.com/mad-ady/odroid-xu4-optimizations/master/cpuset.service
template:
src: templates/ODROID-HC2/cpuset.service.j2
dest: /etc/systemd/system/cpuset.service
mode: '0644'
owner: root
group: root
- name: "ODROID-HC2 TWEAKS: ensure cpuset.service is enabled"
systemd:
name: cpuset.service
enabled: true
- name: "ODROID-HC2 TWEAKS: ensure affinity.service is available"
# from https://raw.githubusercontent.com/mad-ady/odroid-xu4-optimizations/master/affinity.service
template:
src: templates/ODROID-HC2/affinity.service.j2
dest: /etc/systemd/system/affinity.service
mode: '0644'
owner: root
group: root
- name: "ODROID-HC2 TWEAKS: ensure affinity.service is enabled"
systemd:
name: affinity.service
enabled: true
- name: "ODROID-HC2 TWEAKS: ensure tuned profile odroid directory exists"
file:
path: /etc/tuned/odroid
state: directory
mode: '0755'
- name: "ODROID-HC2 TWEAKS: ensure tuned config odroid is present"
template:
src: templates/ODROID-HC2/tuned-profile-odroid.conf.j2
dest: /etc/tuned/odroid/tuned.conf
mode: '0644'
group: root
owner: root
- name: "ODROID-HC2 TWEAKS: ensure tuned script odroid is present"
template:
src: templates/ODROID-HC2/tuned-script-odroid.sh.j2
dest: /etc/tuned/odroid/script.sh
mode: '0755'
group: root
owner: root
- name: "ODROID-HC2 TWEAKS: ensure tuned.service is enabled and running"
systemd:
name: tuned.service
state: started
enabled: true
- block:
- name: "ODROID-HC2 TWEAKS: check which tuned profile is active"
shell: tuned-adm active
register: tuned_active_profile
ignore_errors: yes
changed_when: no
- name: "ODROID-HC2 TWEAKS: activate tuned profile odroid"
shell: tuned-adm profile odroid
when: "tuned_active_profile.stdout.find('Current active profile: odroid') != 0"
- block:
- name: "ODROID-HC2 TWEAKS: ensure irqbalance is installed, since we set IRQ affinity to cores 4-7"
package:
name:
- irqbalance
state: present
- name: "ODROID-HC2 TWEAKS: ensure irqbalance.service is enabled and started"
systemd:
name: irqbalance.service
state: started
enabled: true
- name: "ODROID-HC2 TWEAKS: ensure disk click at shutdown is fixed"
# c.f. https://wiki.odroid.com/odroid-xu4/troubleshooting/shutdown_script
# template is file from https://dn.odroid.com/5422/script/odroid.shutdown
template:
src: templates/ODROID-HC2/odroid-disk.shutdown.j2
dest: /usr/lib/systemd/system-shutdown/odroid-disk.shutdown
mode: '0755'
owner: root
group: root
- name: "ODROID-HC2 TWEAKS: make latest JMS578 Firmware updater available"
get_url:
url: ftp://fileserver.internal.pcfe.net/pub/QNAP-Public/flash_images/Hardkernel/ODROID-HC2/JMS578_Firmware_updater/jms578fwupdater.tgz
checksum: 'sha256:0e729256500ee70bb2caa91c584ff9dca06a262b7437c3b6a6529d5168b9a854'
dest: /root/jms578fwupdater.tgz
mode: '0644'
owner: root
group: root
- name: "ODROID-HC2 TWEAKS: unarchive latest JMS578 Firmware updater"
unarchive:
remote_src: yes
src: /root/jms578fwupdater.tgz
dest: /tmp/
- name: "ensure logrotate and dnf-data are installed"
package:
name:
- dnf-data
- logrotate
state: present
- name: "ensure more agressve log rotation for dnf is in place"
template:
src: templates/logrotate-dnf.j2
dest: /etc/logrotate.d/dnf
mode: '0644'
owner: root
group: root
# https://wiki.odroid.com/odroid-xu4/software/disk_encryption
# luckily ceph-ansible already sets up
# Cipher name: aes
# Cipher mode: xts-plain64
# Hash spec: sha256
# which has the highest performance
# this is not yet working, revisit
# while testing disk perf, just brute someting along the lines of
# for i in `pgrep ceph` ; do taskset -c -p 4-7 $i ; done
# cat /proc/956/task/*/status|grep Cpus_allowed_list
# only use big cores (4-7) by adding to the relevant Service sections
# ExecStartPost=-/bin/sh -c ‘echo $MAINPID | tee -a /sys/fs/cgroup/cpuset/bigcores/tasks’
# - name: "SYSTEMD | CPUAffinity big cores only for all ceph-… services"
# lineinfile:
# path: /etc/systemd/system/ceph-.service.d/ceph.conf
# create: true
# regexp: '^ExecStartPost='
# insertafter: '^[Service]
# line: 'ExecStartPost=-/bin/sh -c `echo $MAINPID | tee -a /sys/fs/cgroup/cpuset/bigcores/tasks`'
Output of Site-Specific Setup Playbook
So that you can get an idea of what the roles I use do, here is the full log
ansible-playbook -i ../inventories/ceph-ODROID-cluster.ini -l odroid-hc2-00 --skip-tags apply_errata odroid-general-setup.yml | tee ../../hugo-blog.pcfe.net/static/code/odroid-general-setup.log
(In this example, I skip applying errata in order to get this log output quicker)
PLAY [odroids] ******************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************ ok: [odroid-hc2-04] TASK [Ensure check-mk-agent-1.5.0p12-1.noarch.rpm is installed, because earlier versions have trouble with thermal zone output] *** changed: [odroid-hc2-04] TASK [ensure /usr/share/check-mk-agent exists] ************************************************************************ changed: [odroid-hc2-04] TASK [symlink plugins and local from /usr/lib/check_mk_agent/ to /usr/share/check-mk-agent/] ************************** changed: [odroid-hc2-04] => (item={'src': 'plugins', 'dest': 'plugins'}) changed: [odroid-hc2-04] => (item={'src': 'local', 'dest': 'local'}) TASK [ensure smart plugin is installed] ******************************************************************************* changed: [odroid-hc2-04] TASK [linux-system-roles.network : Check which services are running] ************************************************** ok: [odroid-hc2-04] TASK [linux-system-roles.network : Check which packages are installed] ************************************************ ok: [odroid-hc2-04] TASK [linux-system-roles.network : Print network provider] ************************************************************ ok: [odroid-hc2-04] => { "msg": "Using network provider: nm" } TASK [linux-system-roles.network : Install packages] ****************************************************************** changed: [odroid-hc2-04] TASK [linux-system-roles.network : Enable network service] ************************************************************ ok: [odroid-hc2-04] TASK [linux-system-roles.network : Configure networking connection profiles] ****************************************** changed: [odroid-hc2-04] TASK [linux-system-roles.network : Re-test connectivity] ************************************************************** ok: [odroid-hc2-04] TASK [pcfe.basic-security-setup : BASIC SEC | ensure selinux is running with enforcing] ******************************* ok: [odroid-hc2-04] TASK [pcfe.basic-security-setup : BASIC SEC | ensure ssh auth is via ssh-key only] ************************************ ok: [odroid-hc2-04] TASK [pcfe.user_owner : USER OWNER | ensure group pcfe exists] ******************************************************** changed: [odroid-hc2-04] TASK [pcfe.user_owner : USER OWNER | ensure user pcfe exists] ********************************************************* changed: [odroid-hc2-04] TASK [pcfe.user_owner : USER OWNER | ensure authorized key for pcfe exists] ******************************************* changed: [odroid-hc2-04] TASK [pcfe.user_owner : USER OWNER | ensure authorized key for root exists] ******************************************* ok: [odroid-hc2-04] TASK [pcfe.comfort : COMFORT | ensure packages for comfortable shell use are installed] ******************************* changed: [odroid-hc2-04] TASK [pcfe.comfort : COMFORT | on Fedora, also ensure fortune is installed] ******************************************* changed: [odroid-hc2-04] TASK [pcfe.comfort : BASH | my additions for pcfe .bashrc] ************************************************************ changed: [odroid-hc2-04] TASK [pcfe.comfort : BASH | my additions for pcfe .bash_profile] ****************************************************** changed: [odroid-hc2-04] TASK [pcfe.comfort : BASH | my additions for root .bashrc] ************************************************************ changed: [odroid-hc2-04] TASK [pcfe.comfort : BASH | my additions for root .bash_profile] ****************************************************** changed: [odroid-hc2-04] TASK [pcfe.comfort : SCREEN | fixup /etc/screenrc] ******************************************************************** changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | EL7, ensure firewalld and its python module are installed] ************************* skipping: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | Fedora, ensure firewalld and its python module are installed] ********************** ok: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | ensure non VM packages for monitoring are installed] ******************************* changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | ensure common packages for monitoring are installed] ******************************* changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | EL, ensure firewalld permits 6556 for check-mk-agent] ****************************** skipping: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | Fedora, ensure firewalld permits 6556 in zone public for check-mk-agent] *********** changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | ensure tarsnap cache is in fileinfo] *********************************************** changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | ensure entropy_avail plugin for Check_MK is present] ******************************* changed: [odroid-hc2-04] TASK [pcfe.check_mk : MONITORING | non-VM ensure used plugins are enabled in check-mk-agent by setting symlink] ******* skipping: [odroid-hc2-04] => (item={'src': 'smart', 'dest': 'smart'}) TASK [pcfe.check_mk : MONITORING | common ensure used plugins are enabled in check-mk-agent by setting symlink] ******* skipping: [odroid-hc2-04] => (item={'src': 'lvm', 'dest': 'lvm'}) skipping: [odroid-hc2-04] => (item={'src': 'mk_inventory', 'dest': 'mk_inventory'}) TASK [pcfe.check_mk : MONITORING | Ensure check_mk.socket is started and enabled] ************************************* changed: [odroid-hc2-04] TASK [PACKAGE | ensure my preferred langpacks are installed] ********************************************************** changed: [odroid-hc2-04] TASK [WATCHDOG | ensure kernel module s3c2410_wdt has correct options configured] ************************************* changed: [odroid-hc2-04] TASK [PACKAGE | ensure watchdog package is installed] ***************************************************************** changed: [odroid-hc2-04] TASK [WATCHDOG | ensure correct watchdog-device is used by watchdog.service] ****************************************** changed: [odroid-hc2-04] TASK [WATCHDOG | ensure timeout is set to 30 seconds for watchdog.service] ******************************************** changed: [odroid-hc2-04] TASK [WATCHDOG | Ensure watchdog.service is disabled] ***************************************************************** ok: [odroid-hc2-04] TASK [SYSTEMD | ensure systemd watchdog is enabled] ******************************************************************* changed: [odroid-hc2-04] TASK [SYSTEMD | ensure systemd shutdown watchdog is enabled] ********************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure needed packages are installed] ******************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure odroid-cpu-control is available] ****************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure cpuset.service is available] ********************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure cpuset.service is enabled] ************************************************************ changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure affinity.service is available] ******************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure affinity.service is enabled] ********************************************************** changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure tuned profile odroid directory exists] ************************************************ changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure tuned config odroid is present] ******************************************************* changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure tuned script odroid is present] ******************************************************* changed: [odroid-hc2-04] TASK [ODROID-HC2 TWEAKS: ensure tuned.service is enabled and running] ************************************************* fatal: [odroid-hc2-04]: FAILED! => {"changed": false, "msg": "Unable to start service tuned.service: Job for tuned.service failed because a fatal signal was delivered causing the control process to dump core.\nSee \"systemctl status tuned.service\" and \"journalctl -xe\" for details.\n"} PLAY RECAP ************************************************************************************************************ odroid-hc2-04 : ok=49 changed=38 unreachable=0 failed=1
My Templates
While most of the template files are from the thread
XU4 4.9 kernel, NAS, Webmin, Owncloud and tweaks or
ODROID-Magazine Feb 2017,
I prefer to have them available locally. The tuned templates and the tiny change to check-mk-agent
’s smart
plugin are my own.
affinity.service.j2
from mad-ady/odroid-xu4-optimizations
[Unit]
Description=Setup special irq affinity
Before=sysinit.target
After=local-fs.target
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/true
ExecStartPost=-/bin/sh -c 'for i in `cat /proc/interrupts | grep usb | cut -d ":" -f 1`; do echo "4-7" > /proc/irq/$i/smp_affinity_list; done'
[Install]
WantedBy=sysinit.target
cpuset.service.j2
from mad-ady/odroid-xu4-optimizations
[Unit]
Description=Setup big/little cgroups
Before=sysinit.target
After=local-fs.target
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/true
ExecStartPost=-/bin/mkdir -p /sys/fs/cgroup/cpuset/littlecores /sys/fs/cgroup/cpuset/bigcores
ExecStartPost=-/bin/sh -c '/bin/echo "0-3" > /sys/fs/cgroup/cpuset/littlecores/cpuset.cpus'
ExecStartPost=-/bin/sh -c '/bin/echo "0"> /sys/fs/cgroup/cpuset/littlecores/cpuset.mems'
ExecStartPost=-/bin/sh -c '/bin/chmod -R 777 /sys/fs/cgroup/cpuset/littlecores'
ExecStartPost=-/bin/sh -c '/bin/echo "4-7"> /sys/fs/cgroup/cpuset/bigcores/cpuset.cpus'
ExecStartPost=-/bin/sh -c '/bin/echo "0"> /sys/fs/cgroup/cpuset/bigcores/cpuset.mems'
ExecStartPost=-/bin/sh -c '/bin/chmod -R 777 /sys/fs/cgroup/cpuset/bigcores'
[Install]
WantedBy=sysinit.target
odroid-cpu-control.j2
from mad-ady/odroid-cpu-control
#!/usr/bin/env perl
use strict;
#use warnings;
use Getopt::Long qw(:config no_ignore_case);
use Data::Dumper;
#
# Code released under GPLv3: http://www.gnu.org/licenses/gpl.html
# v0.3 - Adrian Popa (2016.03.11)
#
#we get our data mainly from /sys/devices/system/cpu
my %options = ();
my $cls = "\033[2J\033[0;0H"; #fancy ANSI escape string
GetOptions(\%options, 'help|h', 'quiet|q', 'list|l', 'set|s', 'governor|g:s', 'cpu|c=s', 'min|m:s', 'max|M:s', 'frequency|f', 'interactive|i=f', 'temperature|t');
#print Dumper(\%options);
if(defined $options{'help'}){
usage();
exit(0);
}
if(defined $options{'set'}){
#interpret the parameters as a set command
#user must be root
die "The script must be run as root in order to apply changes!" if($> != 0);
#see on which cpus you need to set things
my @cpu = getCPUs();
my %before;
if(! exists $options{'quiet'}){
%before = getListing(@cpu);
}
#set the data
foreach my $core (@cpu){
if(defined $options{'governor'}){
open FILE, ">/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_governor" or die "$!";
print FILE $options{'governor'};
close FILE;
}
if(defined $options{'min'}){
open FILE, ">/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_min_freq" or die "$!";
my $number = $options{'min'};
if($options{'min'}=~/([0-9\.]+)(M|G)?/){
$number = $1;
my $scale = $2;
$number = $number * 1000 if($scale eq 'M');
$number = $number * 1000_000 if($scale eq 'G');
}
print FILE $number;
close FILE;
}
if(exists $options{'max'}){
open FILE, ">/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_max_freq" or die "$!";
my $number = $options{'max'};
if($options{'max'}=~/([0-9\.]+)(M|G)?/){
$number = $1;
my $scale = $2;
#print "DBG: $options{'max'}\n";
$number = $number * 1000 if(defined $scale && $scale eq 'M');
$number = $number * 1000_000 if(defined $scale && $scale eq 'G');
}
print FILE $number;
close FILE;
}
if(exists $options{'frequency'}){
#can't set current frequency
}
}
#display results (if any)
if(! exists $options{'quiet'}){
my %after = getListing(@cpu);
# print "DBG: ".Dumper(\%after);
foreach my $core (@cpu){
if(defined $after{$core}{'governor'}){
print "CPU$core: governor $before{$core}{'governor'} -> $after{$core}{'governor'}\n";
}
if(defined $after{$core}{'scale_min'}){
print "CPU$core: min ".humanReadable($before{$core}{'scale_min'})." [".humanReadable($before{$core}{'cpuinfo_min'}) ."] -> ".humanReadable($after{$core}{'scale_min'})." [".humanReadable($after{$core}{'cpuinfo_min'}) ."]\n";
}
if(defined $after{$core}{'scale_max'}){
print "CPU$core: max ".humanReadable($before{$core}{'scale_max'})." [".humanReadable($before{$core}{'cpuinfo_max'}) ."] -> ".humanReadable($after{$core}{'scale_max'})." [".humanReadable($after{$core}{'cpuinfo_max'}) ."]\n";
}
}
}
}
elsif(defined $options{'list'}){
#select all things to display if none is specified
if(! exists $options{'governor'} && ! exists $options{'min'} && ! exists $options{'max'} && ! exists $options{'frequency'} && ! exists $options{'temperature'}){
$options{'governor'} = undef;
$options{'min'} = undef;
$options{'max'} = undef;
$options{'frequency'} = undef;
$options{'temperature'} = undef;
}
#start an infinte loop in case we're in interactive mode
while(1){
my @cpu = getCPUs();
#make output buffered
$|=0;
if(defined $options{'interactive'}){
print $cls;
print "Type CTRL+C to exit.\n";
}
my $temp = 0;
if(defined $options{'temperature'}){
$temp = getTemperature();
}
#print Dumper(\%results);
if(exists $options{'governor'} || exists $options{'frequency'} || exists $options{'min'} || exists $options{'max'}){
my %results = getListing(@cpu);
#display the data -- redundant for, but we might expand/decouple the display later
foreach my $core (@cpu){
my $output.= "CPU$core: ";
$output.="governor $results{$core}{'governor'}\t" if (exists $results{$core}{'governor'});
$output.="current ".humanReadable($results{$core}{'cur'})."\t" if (exists $results{$core}{'cur'});
$output.="min ".humanReadable($results{$core}{'scale_min'})." [".humanReadable($results{$core}{'cpuinfo_min'}) ."]\t" if (exists $results{$core}{'scale_min'});
$output.="max ".humanReadable($results{$core}{'scale_max'})." [".humanReadable($results{$core}{'cpuinfo_max'}) ."] \t" if (exists $results{$core}{'scale_max'});
print $output."\n";
}
}
if(defined $options{'temperature'}){
print "TEMP: ${temp}C\n";
}
if(defined $options{'interactive'}){
#sleep($options{'interactive'});
#sleep fractional seconds without the need of Time::HiRes
select(undef, undef, undef, $options{'interactive'});
}
else{
last; #break the infinite while
}
$|=1;
}
}
else{
usage();
exit(1);
}
sub humanReadable{
my $value = shift;
my %scaleMapping = (
'3' => 'MHz',
'6' => 'GHz',
'9' => 'THz'
);
my $result = $value;
my $scale = 0;
my $break = 0;
while($result >= 1000){
$result = $result/1000;
$scale+=3;
}
return sprintf("%.2f", $result) . $scaleMapping{$scale};
}
sub usage{
my $governors = getData("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors");
print "Usage:
$0 [options]
Options:
-l, --list\t\t\t List a parameter
-s, --set\t\t\t Set a parameter
-g, --governor <governor>\t Select a governor
\t\t\t\t ($governors)
-c, --cpu <number|range>\t The CPU to edit/query. Leave blank for all CPUs. Valid syntax:
\t\t\t\t 0; 0,4; 0,4,5-7; 0-7
-m, --min <number>\t\t The minimum CPU frequency (must be supported by governor and CPU)
-M, --max <number>\t\t The maximum CPU frequency (must be supported by governor and CPU)
-f, --frequency\t\t The current CPU frequency
-t, --temperature\t\t The current CPU temperature
-q, --quiet\t\t\t Don't display much output when setting a parameter
-i, --interactive <number>\t Keep running the list command every number seconds
-h, --help\t\t\t Show this help screen
Examples:
$0 -l\t\t\t\tLists current frequency/governor for all cores
$0 -l -g -f\t\t\t\tLists just governor and current frequency for all cores
$0 -l -c 0,4\t\t\t\tLists all information only for cores 0 and 4
$0 -l -c 0-4\t\t\t\tLists all information for cores 0 to 4
$0 -s -g powersave -m 300M -M 600M\tSets governor, minimum and maximum frequency for all cores
$0 -s -M 1.2G -c 0,4\t\t\tSets maximum frequency on cores 0 and 4
"
}
sub getCPUs{
my @cpu = ();
#see if the user specified a CPU
if(defined $options{'cpu'}){
#parse the CPU option. Could be a number or a sequence
# -c 1
# -c 1,4
# -c 1,4,5-8
my @commas = split(/,/, $options{'cpu'});
foreach my $comma (@commas){
#see if there are any ranges
if($comma=~/([0-9]+)-([0-9]+)/){
my $start = $1;
my $stop = $2;
for($start..$stop){
push @cpu, $_;
}
}
else{
push @cpu, $comma;
}
}
#push @cpu, $options{'cpu'};
}
else{
#get all cpus from the system
my $content = getData("/sys/devices/system/cpu/online");
if($content=~/([0-9]+)(?:-([0-9]+))?/){
my $minCPU = $1;
my $maxCPU = $minCPU;
$maxCPU = $2 if(defined $2);
for($minCPU..$maxCPU){
push @cpu, $_;
}
}
else{
die "Unable to get the list of CPUs";
}
}
return @cpu;
}
sub getData{
my $filename = shift;
my $line = 'N/A';
if(open FILE, "$filename"){
$line = <FILE>;
$line=~s/\r|\n//g;
close FILE;
}
return $line;
}
sub getTemperature{
my $temperatureFile = '/sys/devices/virtual/thermal/thermal_zone0/temp';
my $temp = 0;
if(-f "$temperatureFile"){
$temp = getData($temperatureFile);
$temp = $temp/1000;
}
return $temp;
}
sub getListing{
my %results;
my @cpu = @_;
#get the data
foreach my $core (@cpu){
if(exists $options{'governor'}){
$results{$core}{'governor'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_governor");
}
if(exists $options{'min'}){
$results{$core}{'scale_min'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_min_freq");
$results{$core}{'cpuinfo_min'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/cpuinfo_min_freq");
}
if(exists $options{'max'}){
$results{$core}{'scale_max'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_max_freq");
$results{$core}{'cpuinfo_max'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/cpuinfo_max_freq");
}
if(exists $options{'frequency'}){
$results{$core}{'cur'} = getData("/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_cur_freq");
}
}
return %results;
}
odroid-disk.shutdown.j2
from the ODROID Wiki
#!/bin/bash
exec </dev/null </dev/null 2>/dev/null
export LANG=C LC_ALL=C
###
### actually Fedora's mdadm already drops a
### /usr/lib/systemd/system-shutdown/mdadm.shutdown
### that does that part.
### # In all cases, we want the media to be in quiescent, clean state.
### sync
### [ -x /sbin/mdadm ] && /sbin/mdadm --wait-clean --scan
### Note though that:
### All executables in this directory are executed in parallel, and execution of the action is not continued before all executables finished.
# updated script taken from https://forum.odroid.com/viewtopic.php?f=97&t=29069&start=50#p246051
systemctl list-jobs | egrep -q 'reboot.target.*start' && yval='Y' || yval='y'
# Function used to park all SATA disks.
function ParkDisks() {
if [ -x /sbin/hdparm ]; then
Wait=0
for Dev in /sys/block/sd* ; do
[ -e $Dev ] && /sbin/hdparm -$yval /dev/${Dev##*/} && Wait=5
sleep $Wait
echo 1 > /sys/class/block/${Dev##*/}/device/delete
done
sleep $Wait
fi
}
case "$1" in
# reboot|kexec)
# Do not park disks when rebooting or switching kernels.
# ;;
*)
ParkDisks
;;
esac
smart-for-check-mk.j2
The change below is only necessary until “FEED-3415: linux smart plugin und JMicron USB nach SATA bridges” is implemented on the Check_MK side
--- smart 2019-02-19 20:45:56.477618050 +0100
+++ /root/smart 2019-02-19 20:47:37.678256369 +0100
@@ -142,6 +142,9 @@
MODEL=${MODEL// /-}
DNAME=${DNAME#AMCC_}
DNAME="AMCC_${MODEL}_${DNAME%000000000000}"
+ # 2019-02-19 Patrick C. F. Ernzer - special option in case vendor is JMicron
+ elif [ "$VEND" == "JMicron" ]; then
+ CMD="smartctl -d sat -v 9,raw48 -A $D"
elif [ "$VEND" != "ATA" ] ; then
TEMP=
# create temperature output as expected by checks/smart
tuned-profile-odroid.conf.j2
#
# tuned configuration
#
[main]
summary=ODROID-HC2 tuned profile
[cpu]
# this and 2 sysfs settings as per
# ODROID Magazine Feb 2017
# General-Purpose NAS
governor=ondemand
sampling_down_factor=10
[net]
# c.f. https://bugzilla.redhat.com/show_bug.cgi?id=1026359
enabled=false
[systemd_disk]
type=disk
devices=mmcblk0
#disable_barriers=false
[data_disk]
type=disk
devices=sda
#disable_barriers=false
[usb]
# Since both Network and SATA are on USB3,
# do not allow USB autosuspend
autosuspend=-1
[sysfs]
/sys/devices/system/cpu/cpufreq/ondemand/io_is_busy=1
/sys/devices/system/cpu/cpufreq/ondemand/up_threshold=80
/sys/bus/usb/devices/usb4/power/control=on
/sys/bus/usb/devices/usb6/power/control=on
tuned-script-odroid.sh.j2
#!/bin/sh
. /usr/lib/tuned/functions
start() {
return 0
}
stop() {
return 0
}
process $@