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

  1. Ensure that both python and libselinux-python are installed on the ODROID
  2. Ensure your ODROID-HC2 is in your inventory
  3. Set up variables as needed
  4. Ensure you can ansible … -m ping …
  5. optional: Create an ansible user on the ODROID-HC2 by doing one of
    • using a playbook that connects as user root
    • using shell commands
  6. optional: Run all future playbooks as the ansible user

If you’re interested, there’s also details on my own Ansible setup further below. It includes:

Prerequisites

  1. An OS supported by Ansible on your ODROID-HC2, I installed Fedora on mine
  2. 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.
  • 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:      no
      auto6:      no
      gateway4:   192.168.50.254
      dns:        192.168.50.252
      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 user
  • pcfe.basic-security-setup sets non-negotiable security settings
  • pcfe.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

<span style="color:#75715e"># start by enabling time sync, while my ODROIDs do have the RTC battery add-on, yours might not.</span>
<span style="color:#75715e"># Plus it&#39;s nice to be able to wake up the boards from poweroff</span>
<span style="color:#75715e"># and have the correct time alredy before chrony-wait runs at boot</span>
- <span style="color:#66d9ef">name</span>:         <span style="color:#e6db74">&#34;CHRONYD | ensure chrony-wait is enabled&#34;</span>
  <span style="color:#66d9ef">service</span>:
    <span style="color:#66d9ef">name</span>:       chrony-wait
    <span style="color:#66d9ef">enabled</span>:    <span style="color:#66d9ef">true</span>
- <span style="color:#66d9ef">name</span>:         <span style="color:#e6db74">&#34;CHRONYD | ensure chronyd is enabled and running&#34;</span>
  <span style="color:#66d9ef">service</span>:
    <span style="color:#66d9ef">name</span>:       chronyd
    <span style="color:#66d9ef">enabled</span>:    <span style="color:#66d9ef">true</span>
    <span style="color:#66d9ef">state</span>:      started

<span style="color:#75715e"># enable persistent journal</span>
<span style="color:#75715e"># DAFUQ? re-ran on all odroids, it reported &#39;changed&#39; instead of &#39;ok&#39;?!?</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;JOURNAL | ensure persistent logging for the systemd journal is possible&#34;</span>
  <span style="color:#66d9ef">file</span>:
    <span style="color:#66d9ef">path</span>: /var/log/journal
    <span style="color:#66d9ef">state</span>: directory
    <span style="color:#66d9ef">owner</span>: root
    <span style="color:#66d9ef">group</span>: systemd-journal
    <span style="color:#66d9ef">mode</span>: <span style="color:#ae81ff">0755</span>

<span style="color:#75715e"># enable passwordless sudo for the created ansible user</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;SUDO | enable passwordless sudo for ansible user&#34;</span>
  <span style="color:#66d9ef">copy</span>:
    <span style="color:#66d9ef">dest</span>: /etc/sudoers.d/ansible
    <span style="color:#66d9ef">content</span>: <span style="color:#e6db74">|

ansible ALL=NOPASSWD: ALL owner: root group: root mode: 0440

<span style="color:#75715e"># I do want all errata applied</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;DNF | ensure all updates are applied&#34;</span>
  <span style="color:#66d9ef">dnf</span>:
    <span style="color:#66d9ef">update_cache</span>: yes
    <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#39;*&#39;</span>
    <span style="color:#66d9ef">state</span>: latest
  <span style="color:#66d9ef">tags</span>: 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 settings
  • pcfe.housenet sets up timezone and the use of local package mirrors
  • pcfe.user_owner creates the user ‘pcfe’ (defined in group_vars/) and copies over in my ssh pubkey
  • pcfe.comfort to set up some bits that make my shell use more comfortable
  • pcfe.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.

  • 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'

<span style="color:#75715e"># fix dnf&#39;s &#34;Failed to set locale, defaulting to C&#34; annoyance</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;PACKAGE | ensure my preferred langpacks are installed&#34;</span>
  <span style="color:#66d9ef">package</span>:
    <span style="color:#66d9ef">name</span>:
      - langpacks-en
      - langpacks-en_GB
      - langpacks-de
      - langpacks-fr
    <span style="color:#66d9ef">state</span>: present

<span style="color:#75715e"># enable watchdog based on information from https://wiki.odroid.com/odroid-xu4/application_note/software/linux_watchdog</span>
<span style="color:#75715e"># write watchdog kernel module config, this is needed to enable power cycle</span>
<span style="color:#75715e"># alternatively one could use the kernel boot parameters, but I personally prefer modprobe.d/</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;WATCHDOG | ensure kernel module s3c2410_wdt has correct options configured&#34;</span>
  <span style="color:#66d9ef">lineinfile</span>:
    <span style="color:#66d9ef">path</span>:         /etc/modprobe.d/s3c2410_wdt.conf
    <span style="color:#66d9ef">create</span>:       <span style="color:#66d9ef">true</span>
    <span style="color:#66d9ef">regexp</span>:       <span style="color:#e6db74">&#39;^options &#39;</span>
    <span style="color:#66d9ef">insertafter</span>:  <span style="color:#e6db74">&#39;^#options&#39;</span>
    <span style="color:#66d9ef">line</span>:         <span style="color:#e6db74">&#39;options s3c2410_wdt tmr_margin=30 tmr_atboot=1 nowayout=0&#39;</span>

<span style="color:#75715e"># while testing, configure both watchdog.service and systemd watchdog, but only use the latter for now.</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;PACKAGE | ensure watchdog package is installed&#34;</span>
  <span style="color:#66d9ef">package</span>:
    <span style="color:#66d9ef">name</span>:         watchdog
    <span style="color:#66d9ef">state</span>:        present
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;WATCHDOG | ensure correct watchdog-device is used by watchdog.service&#34;</span>
  <span style="color:#66d9ef">lineinfile</span>:
    <span style="color:#66d9ef">path</span>:         /etc/watchdog.conf
    <span style="color:#66d9ef">regexp</span>:       <span style="color:#e6db74">&#39;^watchdog-device&#39;</span>
    <span style="color:#66d9ef">insertafter</span>:  <span style="color:#e6db74">&#39;^#watchdog-device&#39;</span>
    <span style="color:#66d9ef">line</span>:         <span style="color:#e6db74">&#39;watchdog-device = /dev/watchdog&#39;</span>
<span style="color:#75715e"># values above 32 seconds do not work, cannot set timeout 33 (errno = 22 = &#39;Invalid argument&#39;)</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;WATCHDOG | ensure timeout is set to 30 seconds for watchdog.service&#34;</span>
  <span style="color:#66d9ef">lineinfile</span>:
    <span style="color:#66d9ef">path</span>:         /etc/watchdog.conf
    <span style="color:#66d9ef">regexp</span>:       <span style="color:#e6db74">&#39;^watchdog-timeout&#39;</span>
    <span style="color:#66d9ef">insertafter</span>:  <span style="color:#e6db74">&#39;^#watchdog-timeout&#39;</span>
    <span style="color:#66d9ef">line</span>:         <span style="color:#e6db74">&#39;watchdog-timeout = 30&#39;</span>

<span style="color:#75715e"># testing in progress;</span>
<span style="color:#75715e"># Use systemd watchdog rather than watchdog.service</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;WATCHDOG | Ensure watchdog.service is disabled&#34;</span>
  <span style="color:#66d9ef">systemd</span>:
    <span style="color:#66d9ef">name</span>:         watchdog.service
    <span style="color:#66d9ef">state</span>:        stopped
    <span style="color:#66d9ef">enabled</span>:      <span style="color:#66d9ef">false</span>
    
<span style="color:#75715e"># configure systemd watchdog</span>
<span style="color:#75715e"># c.f. http://0pointer.de/blog/projects/watchdog.html</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;SYSTEMD | ensure systemd watchdog is enabled&#34;</span>
  <span style="color:#66d9ef">lineinfile</span>:
    <span style="color:#66d9ef">path</span>:         /etc/systemd/system.conf
    <span style="color:#66d9ef">regexp</span>:       <span style="color:#e6db74">&#39;^RuntimeWatchdogSec&#39;</span>
    <span style="color:#66d9ef">insertafter</span>:  <span style="color:#e6db74">&#39;EOF&#39;</span>
    <span style="color:#66d9ef">line</span>:         <span style="color:#e6db74">&#39;RuntimeWatchdogSec=30&#39;</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;SYSTEMD | ensure systemd shutdown watchdog is enabled&#34;</span>
  <span style="color:#66d9ef">lineinfile</span>:
    <span style="color:#66d9ef">path</span>:         /etc/systemd/system.conf
    <span style="color:#66d9ef">regexp</span>:       <span style="color:#e6db74">&#39;^ShutdownWatchdogSec&#39;</span>
    <span style="color:#66d9ef">insertafter</span>:  <span style="color:#e6db74">&#39;EOF&#39;</span>
    <span style="color:#66d9ef">line</span>:         <span style="color:#e6db74">&#39;ShutdownWatchdogSec=30&#39;</span>

<span style="color:#75715e"># install and enable rngd</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;PACKAGE | ensure rng-tools package is installed&#34;</span>
  <span style="color:#66d9ef">package</span>:
    <span style="color:#66d9ef">name</span>:         rng-tools
    <span style="color:#66d9ef">state</span>:        present
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;RNGD | ensure rngd.service is enabled and started&#34;</span>
  <span style="color:#66d9ef">systemd</span>:
    <span style="color:#66d9ef">name</span>:         rngd.service
    <span style="color:#66d9ef">state</span>:        started
    <span style="color:#66d9ef">enabled</span>:      <span style="color:#66d9ef">true</span>

<span style="color:#75715e"># most tweaks taken from both </span>
<span style="color:#75715e"># https://forum.odroid.com/viewtopic.php?t=25424 and</span>
<span style="color:#75715e"># https://magazine.odroid.com/wp-content/uploads/ODROID-Magazine-201702.pdf#ODROID%20Magazine%20Issue%2038.indd:.314673:59549</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure needed packages are installed&#34;</span>
  <span style="color:#66d9ef">package</span>:
    <span style="color:#66d9ef">name</span>:
      - libcgroup-tools
      - tuned
      - perl-interpreter
      - hdparm
      - tar
      - unzip
    <span style="color:#66d9ef">state</span>: present
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure odroid-cpu-control is available&#34;</span>
  <span style="color:#75715e"># from https://raw.githubusercontent.com/mad-ady/odroid-cpu-control/master/odroid-cpu-control</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/odroid-cpu-control.j2
    <span style="color:#66d9ef">dest</span>:           /usr/local/bin/odroid-cpu-control
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0755&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure cpuset.service is available&#34;</span>
  <span style="color:#75715e"># from https://raw.githubusercontent.com/mad-ady/odroid-xu4-optimizations/master/cpuset.service</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/cpuset.service.j2
    <span style="color:#66d9ef">dest</span>:           /etc/systemd/system/cpuset.service
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0644&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure cpuset.service is enabled&#34;</span>
  <span style="color:#66d9ef">systemd</span>:
    <span style="color:#66d9ef">name</span>:           cpuset.service
    <span style="color:#66d9ef">enabled</span>:        <span style="color:#66d9ef">true</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure affinity.service is available&#34;</span>
  <span style="color:#75715e"># from https://raw.githubusercontent.com/mad-ady/odroid-xu4-optimizations/master/affinity.service</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/affinity.service.j2
    <span style="color:#66d9ef">dest</span>:           /etc/systemd/system/affinity.service
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0644&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure affinity.service is enabled&#34;</span>
  <span style="color:#66d9ef">systemd</span>:
    <span style="color:#66d9ef">name</span>:           affinity.service
    <span style="color:#66d9ef">enabled</span>:        <span style="color:#66d9ef">true</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure tuned profile odroid directory exists&#34;</span>
  <span style="color:#66d9ef">file</span>:
    <span style="color:#66d9ef">path</span>:           /etc/tuned/odroid
    <span style="color:#66d9ef">state</span>:          directory
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0755&#39;</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure tuned config odroid is present&#34;</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/tuned-profile-odroid.conf.j2
    <span style="color:#66d9ef">dest</span>:           /etc/tuned/odroid/tuned.conf
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0644&#39;</span>
    <span style="color:#66d9ef">group</span>:          root
    <span style="color:#66d9ef">owner</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure tuned script odroid is present&#34;</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/tuned-script-odroid.sh.j2
    <span style="color:#66d9ef">dest</span>:           /etc/tuned/odroid/script.sh
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0755&#39;</span>
    <span style="color:#66d9ef">group</span>:          root
    <span style="color:#66d9ef">owner</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure tuned.service is enabled and running&#34;</span>
  <span style="color:#66d9ef">systemd</span>:
    <span style="color:#66d9ef">name</span>:           tuned.service
    <span style="color:#66d9ef">state</span>:          started
    <span style="color:#66d9ef">enabled</span>:        <span style="color:#66d9ef">true</span>
- <span style="color:#66d9ef">block</span>:
  - <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: check which tuned profile is active&#34;</span>
    <span style="color:#66d9ef">shell</span>:          tuned-adm active
    <span style="color:#66d9ef">register</span>:       tuned_active_profile
    <span style="color:#66d9ef">ignore_errors</span>:  yes
    <span style="color:#66d9ef">changed_when</span>:   no
  - <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: activate tuned profile odroid&#34;</span>
    <span style="color:#66d9ef">shell</span>:          tuned-adm profile odroid
    <span style="color:#66d9ef">when</span>:           <span style="color:#e6db74">&#34;tuned_active_profile.stdout.find(&#39;Current active profile: odroid&#39;) != 0&#34;</span>
- <span style="color:#66d9ef">block</span>:
  - <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure irqbalance is installed, since we set IRQ affinity to cores 4-7&#34;</span>
    <span style="color:#66d9ef">package</span>:
      <span style="color:#66d9ef">name</span>:
        - irqbalance
      <span style="color:#66d9ef">state</span>: present
  - <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure irqbalance.service is enabled and started&#34;</span>
    <span style="color:#66d9ef">systemd</span>:
      <span style="color:#66d9ef">name</span>:         irqbalance.service
      <span style="color:#66d9ef">state</span>:        started
      <span style="color:#66d9ef">enabled</span>:      <span style="color:#66d9ef">true</span>
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: ensure disk click at shutdown is fixed&#34;</span>
  <span style="color:#75715e"># c.f. https://wiki.odroid.com/odroid-xu4/troubleshooting/shutdown_script</span>
  <span style="color:#75715e"># template is file from https://dn.odroid.com/5422/script/odroid.shutdown</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/ODROID-HC2/odroid-disk.shutdown.j2
    <span style="color:#66d9ef">dest</span>:           /usr/lib/systemd/system-shutdown/odroid-disk.shutdown
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0755&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: make latest JMS578 Firmware updater available&#34;</span>
  <span style="color:#66d9ef">get_url</span>:
    <span style="color:#66d9ef">url</span>:            ftp://fileserver.internal.pcfe.net/pub/QNAP-Public/flash_images/Hardkernel/ODROID-HC2/JMS578_Firmware_updater/jms578fwupdater.tgz
    <span style="color:#66d9ef">checksum</span>:       <span style="color:#e6db74">&#39;sha256:0e729256500ee70bb2caa91c584ff9dca06a262b7437c3b6a6529d5168b9a854&#39;</span>
    <span style="color:#66d9ef">dest</span>:           /root/jms578fwupdater.tgz
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0644&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ODROID-HC2 TWEAKS: unarchive latest JMS578 Firmware updater&#34;</span>
  <span style="color:#66d9ef">unarchive</span>:
    <span style="color:#66d9ef">remote_src</span>:     yes
    <span style="color:#66d9ef">src</span>:            /root/jms578fwupdater.tgz
    <span style="color:#66d9ef">dest</span>:           /tmp/
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ensure logrotate and dnf-data are installed&#34;</span>
  <span style="color:#66d9ef">package</span>:
    <span style="color:#66d9ef">name</span>:
      - dnf-data
      - logrotate
    <span style="color:#66d9ef">state</span>: present
- <span style="color:#66d9ef">name</span>: <span style="color:#e6db74">&#34;ensure more agressve log rotation for dnf is in place&#34;</span>
  <span style="color:#66d9ef">template</span>:
    <span style="color:#66d9ef">src</span>:            templates/logrotate-dnf.j2
    <span style="color:#66d9ef">dest</span>:           /etc/logrotate.d/dnf
    <span style="color:#66d9ef">mode</span>:           <span style="color:#e6db74">&#39;0644&#39;</span>
    <span style="color:#66d9ef">owner</span>:          root
    <span style="color:#66d9ef">group</span>:          root
<span style="color:#75715e"># https://wiki.odroid.com/odroid-xu4/software/disk_encryption</span>
<span style="color:#75715e"># luckily ceph-ansible already sets up</span>
<span style="color:#75715e">#   Cipher name:    aes</span>
<span style="color:#75715e">#   Cipher mode:    xts-plain64</span>
<span style="color:#75715e">#   Hash spec:      sha256</span>
<span style="color:#75715e"># which has the highest performance</span>


<span style="color:#75715e"># this is not yet working, revisit</span>
<span style="color:#75715e"># while testing disk perf, just brute someting along the lines of</span>
<span style="color:#75715e"># for i in `pgrep ceph` ; do taskset -c -p 4-7 $i ; done</span>
<span style="color:#75715e"># cat /proc/956/task/*/status|grep Cpus_allowed_list</span>
<span style="color:#75715e"># only use big cores (4-7) by adding to the relevant Service sections</span>
<span style="color:#75715e"># ExecStartPost=-/bin/sh -c ‘echo $MAINPID | tee -a /sys/fs/cgroup/cpuset/bigcores/tasks’</span>
<span style="color:#75715e"># - name: &#34;SYSTEMD | CPUAffinity big cores only for all ceph-… services&#34;</span>
<span style="color:#75715e">#   lineinfile:</span>
<span style="color:#75715e">#     path:         /etc/systemd/system/ceph-.service.d/ceph.conf</span>
<span style="color:#75715e">#     create:       true</span>
<span style="color:#75715e">#     regexp:       &#39;^ExecStartPost=&#39;</span>
<span style="color:#75715e">#     insertafter:  &#39;^[Service]</span>
<span style="color:#75715e">#     line:         &#39;ExecStartPost=-/bin/sh -c `echo $MAINPID | tee -a /sys/fs/cgroup/cpuset/bigcores/tasks`&#39;</span>

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 &#34;:&#34; -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(</span>%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

<span style="color:#75715e">#user must be root</span>
die <span style="color:#e6db74">&#34;The script must be run as root in order to apply changes!&#34;</span> <span style="color:#66d9ef">if</span>($&gt; <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span>);

<span style="color:#75715e">#see on which cpus you need to set things</span>
<span style="color:#66d9ef">my</span> @cpu <span style="color:#f92672">=</span> getCPUs();
<span style="color:#66d9ef">my</span> %before;
<span style="color:#66d9ef">if</span>(<span style="color:#f92672">!</span> exists $options{<span style="color:#e6db74">&#39;quiet&#39;</span>}){
    %before <span style="color:#f92672">=</span> getListing(@cpu);
}

<span style="color:#75715e">#set the data</span>
<span style="color:#66d9ef">foreach</span> <span style="color:#66d9ef">my</span> $core (@cpu){
    <span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;governor&#39;</span>}){
        open FILE, <span style="color:#e6db74">&#34;&gt;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_governor&#34;</span> <span style="color:#f92672">or</span> die <span style="color:#e6db74">&#34;$!&#34;</span>;
        <span style="color:#66d9ef">print</span> FILE $options{<span style="color:#e6db74">&#39;governor&#39;</span>};
        close FILE;
    }
    <span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;min&#39;</span>}){
        open FILE, <span style="color:#e6db74">&#34;&gt;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_min_freq&#34;</span> <span style="color:#f92672">or</span> die <span style="color:#e6db74">&#34;$!&#34;</span>;
        <span style="color:#66d9ef">my</span> $number <span style="color:#f92672">=</span> $options{<span style="color:#e6db74">&#39;min&#39;</span>};
        <span style="color:#66d9ef">if</span>($options{<span style="color:#e6db74">&#39;min&#39;</span>}<span style="color:#f92672">=~</span><span style="color:#e6db74">/([0-9\.]+)(M|G)?/</span>){
            $number <span style="color:#f92672">=</span> $1;
            <span style="color:#66d9ef">my</span> $scale <span style="color:#f92672">=</span> $2;
            $number <span style="color:#f92672">=</span> $number <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span> <span style="color:#66d9ef">if</span>($scale <span style="color:#f92672">eq</span> <span style="color:#e6db74">&#39;M&#39;</span>);
            $number <span style="color:#f92672">=</span> $number <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000_000</span> <span style="color:#66d9ef">if</span>($scale <span style="color:#f92672">eq</span> <span style="color:#e6db74">&#39;G&#39;</span>);
        }
        <span style="color:#66d9ef">print</span> FILE $number;
        close FILE;
    }
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;max&#39;</span>}){
        open FILE, <span style="color:#e6db74">&#34;&gt;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_max_freq&#34;</span> <span style="color:#f92672">or</span> die <span style="color:#e6db74">&#34;$!&#34;</span>;
        <span style="color:#66d9ef">my</span> $number <span style="color:#f92672">=</span> $options{<span style="color:#e6db74">&#39;max&#39;</span>};
        <span style="color:#66d9ef">if</span>($options{<span style="color:#e6db74">&#39;max&#39;</span>}<span style="color:#f92672">=~</span><span style="color:#e6db74">/([0-9\.]+)(M|G)?/</span>){
            $number <span style="color:#f92672">=</span> $1;
            <span style="color:#66d9ef">my</span> $scale <span style="color:#f92672">=</span> $2;
            <span style="color:#75715e">#print &#34;DBG: $options{&#39;max&#39;}\n&#34;;</span>
            $number <span style="color:#f92672">=</span> $number <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span> <span style="color:#66d9ef">if</span>(defined $scale <span style="color:#f92672">&amp;&amp;</span> $scale <span style="color:#f92672">eq</span> <span style="color:#e6db74">&#39;M&#39;</span>);
            $number <span style="color:#f92672">=</span> $number <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000_000</span> <span style="color:#66d9ef">if</span>(defined $scale <span style="color:#f92672">&amp;&amp;</span> $scale <span style="color:#f92672">eq</span> <span style="color:#e6db74">&#39;G&#39;</span>);
        }
        <span style="color:#66d9ef">print</span> FILE $number;
        close FILE;
    }
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;frequency&#39;</span>}){
        <span style="color:#75715e">#can&#39;t set current frequency</span>
    }
}

<span style="color:#75715e">#display results (if any)</span>
<span style="color:#66d9ef">if</span>(<span style="color:#f92672">!</span> exists $options{<span style="color:#e6db74">&#39;quiet&#39;</span>}){
    <span style="color:#66d9ef">my</span> %after <span style="color:#f92672">=</span> getListing(@cpu);

# print "DBG: ".Dumper(%after); foreach my $core (@cpu){

        <span style="color:#66d9ef">if</span>(defined $after{$core}{<span style="color:#e6db74">&#39;governor&#39;</span>}){
            <span style="color:#66d9ef">print</span> <span style="color:#e6db74">&#34;CPU$core: governor $before{$core}{&#39;governor&#39;} -&gt; $after{$core}{&#39;governor&#39;}\n&#34;</span>;
        }
        <span style="color:#66d9ef">if</span>(defined $after{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>}){
            <span style="color:#66d9ef">print</span> <span style="color:#e6db74">&#34;CPU$core: min &#34;</span><span style="color:#f92672">.</span>humanReadable($before{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($before{$core}{<span style="color:#e6db74">&#39;cpuinfo_min&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;] -&gt; &#34;</span><span style="color:#f92672">.</span>humanReadable($after{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($after{$core}{<span style="color:#e6db74">&#39;cpuinfo_min&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;]\n&#34;</span>;
        }
        <span style="color:#66d9ef">if</span>(defined $after{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>}){
            <span style="color:#66d9ef">print</span> <span style="color:#e6db74">&#34;CPU$core: max &#34;</span><span style="color:#f92672">.</span>humanReadable($before{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($before{$core}{<span style="color:#e6db74">&#39;cpuinfo_max&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;] -&gt; &#34;</span><span style="color:#f92672">.</span>humanReadable($after{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($after{$core}{<span style="color:#e6db74">&#39;cpuinfo_max&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;]\n&#34;</span>;
        }
    }
}

} 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();

    <span style="color:#75715e">#make output buffered</span>
    $|<span style="color:#f92672">=</span><span style="color:#ae81ff">0</span>;

<span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;interactive&#39;</span>}){
    <span style="color:#66d9ef">print</span> $cls;
    <span style="color:#66d9ef">print</span> <span style="color:#e6db74">&#34;Type CTRL+C to exit.\n&#34;</span>;
}
    
<span style="color:#66d9ef">my</span> $temp <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;temperature&#39;</span>}){
    $temp <span style="color:#f92672">=</span> getTemperature();
}

<span style="color:#75715e">#print Dumper(\%results);</span>
<span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;governor&#39;</span>} <span style="color:#f92672">||</span> exists $options{<span style="color:#e6db74">&#39;frequency&#39;</span>} <span style="color:#f92672">||</span> exists $options{<span style="color:#e6db74">&#39;min&#39;</span>} <span style="color:#f92672">||</span> exists $options{<span style="color:#e6db74">&#39;max&#39;</span>}){
    <span style="color:#66d9ef">my</span> %results <span style="color:#f92672">=</span> getListing(@cpu);
    <span style="color:#75715e">#display the data -- redundant for, but we might expand/decouple the display later</span>
<span style="color:#66d9ef">foreach</span> <span style="color:#66d9ef">my</span> $core (@cpu){
    
    <span style="color:#66d9ef">my</span> $output<span style="color:#f92672">.=</span> <span style="color:#e6db74">&#34;CPU$core: &#34;</span>;
        $output<span style="color:#f92672">.=</span><span style="color:#e6db74">&#34;governor $results{$core}{&#39;governor&#39;}\t&#34;</span> <span style="color:#66d9ef">if</span> (exists $results{$core}{<span style="color:#e6db74">&#39;governor&#39;</span>});
        $output<span style="color:#f92672">.=</span><span style="color:#e6db74">&#34;current &#34;</span><span style="color:#f92672">.</span>humanReadable($results{$core}{<span style="color:#e6db74">&#39;cur&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;\t&#34;</span> <span style="color:#66d9ef">if</span> (exists $results{$core}{<span style="color:#e6db74">&#39;cur&#39;</span>});
        $output<span style="color:#f92672">.=</span><span style="color:#e6db74">&#34;min &#34;</span><span style="color:#f92672">.</span>humanReadable($results{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($results{$core}{<span style="color:#e6db74">&#39;cpuinfo_min&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;]\t&#34;</span> <span style="color:#66d9ef">if</span> (exists $results{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>});
        $output<span style="color:#f92672">.=</span><span style="color:#e6db74">&#34;max &#34;</span><span style="color:#f92672">.</span>humanReadable($results{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>})<span style="color:#f92672">.</span><span style="color:#e6db74">&#34; [&#34;</span><span style="color:#f92672">.</span>humanReadable($results{$core}{<span style="color:#e6db74">&#39;cpuinfo_max&#39;</span>}) <span style="color:#f92672">.</span><span style="color:#e6db74">&#34;] \t&#34;</span> <span style="color:#66d9ef">if</span> (exists $results{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>});
    
    
        <span style="color:#66d9ef">print</span> $output<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;\n&#34;</span>;
}
}
<span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;temperature&#39;</span>}){
    <span style="color:#66d9ef">print</span> <span style="color:#e6db74">&#34;TEMP: ${temp}C\n&#34;</span>;
}

<span style="color:#66d9ef">if</span>(defined $options{<span style="color:#e6db74">&#39;interactive&#39;</span>}){
    <span style="color:#75715e">#sleep($options{&#39;interactive&#39;});</span>
    <span style="color:#75715e">#sleep fractional seconds without the need of Time::HiRes</span>
    select(undef, undef, undef, $options{<span style="color:#e6db74">&#39;interactive&#39;</span>});
}
<span style="color:#66d9ef">else</span>{
    <span style="color:#66d9ef">last</span>; <span style="color:#75715e">#break the infinite while</span>
}
$|<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>;
}

} else{ usage(); exit(1); }

sub humanReadable{ my $value = shift; my %scaleMapping = ( '3' => 'MHz', '6' => 'GHz', '9' => 'THz' );

<span style="color:#66d9ef">my</span> $result <span style="color:#f92672">=</span> $value;
<span style="color:#66d9ef">my</span> $scale <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">my</span> $break <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">while</span>($result <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">1000</span>){
    $result <span style="color:#f92672">=</span> $result<span style="color:#f92672">/</span><span style="color:#ae81ff">1000</span>;
    $scale<span style="color:#f92672">+=</span><span style="color:#ae81ff">3</span>;
}
<span style="color:#66d9ef">return</span> sprintf(<span style="color:#e6db74">&#34;%.2f&#34;</span>, $result) <span style="color:#f92672">.</span> $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 = @_;

<span style="color:#75715e">#get the data</span>
<span style="color:#66d9ef">foreach</span> <span style="color:#66d9ef">my</span> $core (@cpu){
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;governor&#39;</span>}){
        $results{$core}{<span style="color:#e6db74">&#39;governor&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_governor&#34;</span>);
    }
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;min&#39;</span>}){
        $results{$core}{<span style="color:#e6db74">&#39;scale_min&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_min_freq&#34;</span>);
        $results{$core}{<span style="color:#e6db74">&#39;cpuinfo_min&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/cpuinfo_min_freq&#34;</span>);
    }
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;max&#39;</span>}){
        $results{$core}{<span style="color:#e6db74">&#39;scale_max&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_max_freq&#34;</span>);
        $results{$core}{<span style="color:#e6db74">&#39;cpuinfo_max&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/cpuinfo_max_freq&#34;</span>);
    }
    <span style="color:#66d9ef">if</span>(exists $options{<span style="color:#e6db74">&#39;frequency&#39;</span>}){
        $results{$core}{<span style="color:#e6db74">&#39;cur&#39;</span>} <span style="color:#f92672">=</span> getData(<span style="color:#e6db74">&#34;/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_cur_freq&#34;</span>);
    }
}

<span style="color:#66d9ef">return</span> %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&amp;t=29069&amp;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() {

    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>

}

stop() {

    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>

}

process $@