RSS

Archive for October, 2024

Repeatable Deployments 5 – NVMe Base Duo

Monday, October 21st, 2024

NVMe Base Duo Banner

A few weeks ago we looked at using the Pimoroni NVMe Base to add 500 GBytes of storage to a Raspberry Pi, first manually and then using Ansible.

A few days ago I started to look at doing the same but this time with the NVMe Base Duo. This would allow the addition of two drives to the Raspberry Pi. Should be simple, right?

TL;DR The scripts and instructions for running them can be found in the AnsibleNVMe GitHub repository.

Setting up the Hardware

As with the NVMe Base, setting up the NVMe Base Duo was simple, just follow the installation instructions on theproduct page. Again, the most difficult part was connecting the NVMe Base Duo board to the Raspberry Pi using the flat flex connector.

A quick check of the /dev directory shows the two drives as devices:

clusteruser@TestServer:~ $ ls /dev/nv*
/dev/nvme0  /dev/nvme0n1  /dev/nvme1  /dev/nvme1n1

Setting up the two drives should be a case of running the configuration script from the previous post with two different device / mount point names, namely:

  • nvme0 / nvme0n1
  • nvme1 / nvme1n1

Ansible tasks should allow us to reuse the commands used to mount a single drive on the NVMe Base without repeating the instructions with copy/paste.

Ansible Tasks

First thing to do is identify the tasks that should be executed on both drives. These are found in the ConfigureNVMeBase.yml file. They make up the bulk of the file. These tasks are:

- name: Format the NVMe drive {{ nvmebase_device_name }}
  command: mkfs.ext4 /dev/{{ nvmebase_device_name }} -L Data
  when: format_nvmebase | bool

- name: Make the mount point for {{ nvmebase_device_name }}
  command: mkdir /mnt/{{ nvmebase_device_name }}

- name: Mount the newly formatted drive ({{ nvmebase_device_name }})
  command: mount /dev/{{ nvmebase_device_name }} /mnt/{{ nvmebase_device_name }}

- name: Make sure that {{ ansible_user }} can read and write to the mount point
  command: chown -R {{ ansible_user }}:{{ ansible_user }} /mnt/{{ nvmebase_device_name }}

- name: Get the UUID of {{ nvmebase_device_name }}
  command: blkid /dev/{{ nvmebase_device_name }}
  register: blkid_output

- name: Extract UUID from blkid output
  set_fact:
    device_uuid: "{{ blkid_output.stdout | regex_search('UUID=\"([^\"]+)\"', '\\1') }}"

- name: Clean the extracted UUID
  set_fact:
    clean_uuid: "{{ device_uuid | regex_replace('\\[', '') | regex_replace(']', '') |  regex_replace(\"'\" '') }}"

- name: Add UUID entry for {{ nvmebase_device_name }} to /etc/fstab
  lineinfile:
    path: /etc/fstab
    line: "UUID={{ clean_uuid }} /mnt/{{ nvmebase_device_name }} ext4 defaults,auto,users,rw,nofail,noatime 0 0"
    state: present
    create: yes

Breaking these instruction out into a new file, ConfigureNVMeBaseTasks.yml file gives us the consolidated tasks list. The device and drive mount point are derived from the Ansible variable nvmebase_device_name which is set in the calling script as follows:

- include_tasks: ConfigureNVMeDriveTasks.yml
  vars:
	  nvmebase_device_name: nvme0n1

The ansible_user variable (used in the chown command in the tasks file) is taken from the group_vars/all.yml file.

And for the second drive we would use:

- include_tasks: ConfigureNVMeDriveTasks.yml
  vars:
	  nvmebase_device_name: nvme1n1
  when: nvme_duo == true

Note the addition of the when clause to only execute the tasks in the ConfigureNVMeDriveTasks.yml if the nvme_duo variable is true. This clause will also be used when Samba is configured.

Install Samba (Optional)

The installation of Samba follows similar steps as detailed in the Adding NVMe Base using Ansible post. The only addition is to add the second drive to the configuration section of the script.

Change Hostname (Optional)

One final, optional step is to change the name of the Raspberry Pi. This is useful when a number of devices are being configured. This step requires the hostname variable being set in the group_vars/all.yml file. Execute the ChangeHostname.yml script once the variable has been changed. Note that the script may fail following the reboot step as Ansible tries to reconnect with the Raspberry Pi using the old host name.

Lessons Learned

For some reason which was never tracked down, the installation of the sometimes failed on the NVMe Base Duo with access permission issues. The access issue presents itself on the Samba shares and also when attempting to use the drive when logged into the Raspberry Pi. This was resolved by setting the ansible_user variable in the group_vars/all.yml file.

The first installation of the NVMe Base Duo added the PCIe Generation 3 support. This caused some issues accessing the devices in the /dev directory. Removing this support allowed both of the drives to be accessed.

Conclusion

Breaking the drive installation and configuration into a new tasks file allows Ansible to reuse the same steps for two different devices. Couple this with when clauses allows changes to the control flow when deploying to two different types of devices.

Repeatable Deployments 4 – Variables and Samba

Monday, October 14th, 2024

Repeatable Deployments 4 Banner

The previous post, Adding NVMe Drive Automatically used Ansible to automatically add and format a SSD drive mounted on the Pimironi NVMe Base to a Raspberry Pi. This post will extend the work by using Ansible variables and configuration files to allow the following:

  • Control the name of the mount point for the SSD
  • Determine if the SSD should be formatted before mounting
  • Add configuration to simplify the command line

Additionally, this post covers the installation of Samba to allow the contents of the mounted drive available to an eternal computer.

The code for this this post is available on GitHub with the code for this article available tagged as Repeatable Deployments 4.

Configuration

Ansible has a number of options for configuration files and the one being used here is the ansible.cfg file in the base directory for the ansible scripts. In this simple case, the ansible.cfg file contains the following:

[defaults]
inventory = ./hosts.ini

These two lines allow the simplification of the command line and also the Ansible scripts.

hosts = ./hosts.ini

Name of the file containing the list of host systems being targetted. In the previous post this was inventory.yml. This has been changed here to hosts.ini to fit in with more conventional Ansible usage. Adding this line to the file allows us to remove the -i inventory.ini from the command line.

The hosts.ini contents remain the same as the inventory.ini file in the previous post.

Variables

The group_vars/all.yml file contains the variable definitions that will be applied to all of the scripts. The variables are as follows:

---
default_user: clusteruser
nvmebase_mount_point: nvme0
format_nvmebase: false

default_user

Name of the default user for the device. This is used as part of the Samba installation. This should match the user name used to install and update the operating system on the Raspberry Pi.

Default: clusteruser

nvmebase_mount_point

Name of the mount point for the NVMe drive.

Default: nvme0

format_nvmebase

This determines if the NVMe drive should be formatted (have a new file system created on the drive) as part of the installation process.

Set this to true for new drives (or drives where the data is to be discarded). Set this to false to preserve the contents of the drive. Note that setting format_nvmebase to false for an unformatted (new) drive will cause the ConfigureNVMeBase.yml script to fail.

Default: false

Install Samba

The next addition is the installation of Samba allowing sharing of files on the Pi to the local network.

- name: Samba
  hosts: raspberrypi

  tasks:
  - name: Install Samba
    become: yes
    apt:
      pkg:
        - samba
        - samba-common-bin
        - cifs-utils 
      state: present
      update_cache: true
  
  - name: Set up Samba configuration
    become: yes
    blockinfile:
      path: /etc/samba/smb.conf
      block: |
        [share]
            path = /mnt/{{ nvmebase_mount_point }}
            read only = no
            public = yes
            writable = yes
            force user={{ default_user }}

This breaks down to two steps:

  • Install Samba
  • Configure Samba

The configuration puts the Samba share on the drive connected to the NVMe Base board. This allows for the USB system drive to be reflashed whilst preserving any data that has been created on the NVMe Base drive.

The share will be a writable share accessible to any users on the network. Normally this is not desirable but it is acceptable for a device on a small restricted network.

Lessons Learned

One issue initially encountered with the Samba share was accessibility. The share was visible over the local network but only in read-only mode. Adding the following to the configuration corrected this issue:

force user={{ default_user }}

Where default_user is defined in the global_vars/all.yml file.

This script is run in the same manner as the other Ansible scripts, ansible-playbook InstallSamba.yml.

Conclusion

Using variables allows flexibility in the installation of the NVMe drive, namely, data preservation across installations. This makes the system ideal for use as a monitoring system gathering data from devices on the network while allowing the Raspberry Pi to be updated with new software configurations while still preserving the ability to setup a new system.