Most common storage for Rasperry Pi are SD Cards.
Unfortunately they are not a very reliable memory.
From time to time you need to replace one for another.
To make this process easier you can create your own customized raspbian image.
Recently one of my rpis stop working properly. Reason unknown but dmesg showed few fs errors.
Usually I would download raspbian image and install it from scratch.
Unfortunately it is not very pleasant experience:
- if you use wifi the default raspbian has no config and is not able to connect to it
- raspbian has ssh turned off
- you need to plug keyboard and hdmi to fix above issues
- then you can install your software, config the machine
Most of my servers, cloud services, workstation I provision with ansible so the solution for the problem was obvious.
I only needed to find a way to alter raspian image with my own configuration, add some provisioning script and record it to an SD.
Here is my sample script. Read comments for explanation:
playbook.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#!/usr/bin/ansible-playbook -i 'localhost,'
---
- hosts: localhost
connection: local
tasks:
- name: Download raspbian
get_url:
url: https://downloads.raspberrypi.org/raspbian_lite_latest
dest: raspbian-lite.zip
mode: '0440'
- name: Extract raspbian-lite.zip
unarchive:
src: raspbian-lite.zip
dest: .
- name: Rename
raw: mv *-raspbian-*-lite.img raspbian-lite.img
- name: Unmount all mount dirs just in case
raw: umount ./mount_boot ; umount ./mount_root
failed_when: false
become: true
# Modifying Boot partition
# Using method from https://learnaddict.com/2016/02/23/modifying-a-raspberry-pi-raspbian-image-on-linux/ to calculate partition offsets
- name: Get boot offset
raw: fdisk -l raspbian-lite.img | grep raspbian-lite.img1 | sed 's/\s\{1,\}/\t/g' | cut -f2
register: "offset_boot"
- name: Create mount_boot
file: path=./mount_boot state=directory
- name: Mount boot
raw: mount -v -o offset={{offset_boot.stdout | int * 512}} -t vfat raspbian-lite.img ./mount_boot
become: true
- name: Copy boot config.txt
copy:
src: ./files/config.txt
dest: ./mount_boot/config.txt
owner: root
group: root
mode: '0644'
become: true
- name: Unmount boot
raw: umount ./mount_boot
failed_when: false
become: true
# Modifying Root partition
- name: Get root offset
raw: fdisk -l raspbian-lite.img | grep raspbian-lite.img2 | sed 's/\s\{1,\}/\t/g' | cut -f2
register: "offset_root"
- name: Unmount root
raw: umount ./mount_root
failed_when: false
become: true
- name: Create mount_root
file: path=./mount_boot state=directory
- name: Mount root
raw: mount -v -o offset={{offset_root.stdout | int * 512}} -t ext4 raspbian-lite.img ./mount_root
become: true
# Provision script
- name: Create flag file which indicates that rpi need provisioning
file:
path: ./mount_root/root/requires_provisioning
state: touch
owner: root
group: root
mode: '0644'
become: true
- name: Copy provisioning service
copy:
src: ./files/provision.service
dest: ./mount_root/lib/systemd/system
owner: root
group: root
mode: '0644'
become: true
- name: Create symbolic link
file:
src: "/lib/systemd/system/provision.service"
dest: "./mount_root/etc/systemd/system/multi-user.target.wants/provision.service"
state: link
force: yes
become: true
- name: Copy provisioning script
copy:
src: ./files/provision.sh
dest: ./mount_root/root/provision.sh
owner: root
group: root
mode: '0744'
become: true
# Config WiFi
- name: Get WiFi SSID in Ubuntu
raw: iwgetid -r
register: "wifi_ssid"
when: config_wifi == 'y'
- name: Get WiFi password in Ubuntu
raw: cat /etc/NetworkManager/system-connections/{{wifi_ssid.stdout | trim}} | grep ^psk= | sed s/^psk=//g
register: "wifi_pass"
become: true
when: config_wifi == 'y'
- name: Write WiFi credentials to Root partition
template:
src: wpa_supplicant.conf
dest: ./mount_root/etc/wpa_supplicant/wpa_supplicant.conf
owner: root
group: root
mode: '0600'
become: true
when: config_wifi == 'y'
- name: Unmount root
raw: umount ./mount_root
failed_when: false
become: true
- name: Write to SD
raw: dd if="raspbian-lite.img" of={{dest}} bs=4M oflag=dsync status=progress
become: true
vars:
config_wifi: 'n'
vars_prompt:
- name: dest
prompt: "Destination"
default: "/dev/mmcblk0"
private: no
|
files/provision.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#!/bin/sh
set -e
set -u
if [ ! -f /root/requires_provisioning ]; then
exit 0
fi
sudo systemctl enable ssh || {
echo "Unable to enable ssh"
exit 1
}
sudo systemctl start ssh || {
echo "Unable to start ssh"
exit 1
}
sudo apt update || {
echo "Unable to apt update"
exit 2
}
sudo apt upgrade -y || {
echo "Unable to apt upgrade"
exit 2
}
sudo apt install ansible -y || {
echo "Unable to install ansible"
exit 2
}
rm -f /root/requires_provisioning
|
templates/wpa_supplicant.conf
network={
ssid="{{wifi_ssid.stdout | trim}}"
psk="{{wifi_pass.stdout | trim}}"
}