-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathbase.sh
More file actions
212 lines (180 loc) · 5.65 KB
/
Copy pathbase.sh
File metadata and controls
212 lines (180 loc) · 5.65 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/bin/bash
if [ -d "/shells/software/qemu-8.2.9/bin" ]; then
export PATH="/shells/software/qemu-8.2.9/bin:$PATH"
fi
QEMUIMG="$(command -v qemu-img)"
QEMUSD="$(command -v qemu-storage-daemon)"
NBDCL="$(command -v nbd-client)"
# various settings
NBD="/dev/nbd2"
RESDIR="$PWD/res"
SCRIPTSDIR="$PWD/scripts"
TMPIMG="work$$.qcow2"
API_PREFIX="https://ws.atonline.com/_special/rest/"
BLOCKSIZE=512
if [ -d /shells ]; then
WORK="/shells/work"
else
WORK="$PWD/work"
fi
if [ x"$USER" = x"root" ]; then
modprobe nbd
fi
DATE=$(date +'%Y%m%d')
perform_clean() {
if [ -d "$WORK" ]; then
fuser --kill --ismountpoint --mount "$WORK" && sleep 1 || true
umount 2>/dev/null "$WORK/var/cache/apt/archives" || true
umount 2>/dev/null "$WORK/proc" "$WORK/sys" "$WORK/dev/pts" "$WORK/dev" || umount 2>/dev/null -l "$WORK/proc" "$WORK/sys" "$WORK/dev" || true
umount 2>/dev/null "$WORK" || true
"$NBDCL" 2>/dev/null -d "$NBD" || true
killall qemu-storage-daemon || true
# should be empty after umount
rmdir "$WORK"
fi
}
create_empty() {
perform_clean
echo "Creating and partitionning $TMPIMG..."
"$QEMUIMG" create -f qcow2 "$TMPIMG" 10G
"$QEMUSD" --daemonize --pidfile qemusd.$$.pid --blockdev "driver=qcow2,file.driver=file,file.filename=$TMPIMG,node-name=disk0" --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock --export type=nbd,id=exp0,node-name=disk0,name=disk0,writable=on
"$NBDCL" -unix /tmp/nbd.sock -N disk0 -b "$BLOCKSIZE" "$NBD"
sleep 0.5
parted --script -a optimal -- "$NBD" mklabel gpt mkpart primary ext4 1MiB -2048s
sleep 0.5 # wait for /dev to update
echo "Formatting and mounting..."
mkfs.ext4 -L root "$NBD"p1
mkdir "$WORK"
mount "$NBD"p1 "$WORK"
}
prepare() {
perform_clean
if [ x"$1" != x ]; then
echo '*****'
echo "** Preparing new environment based on $1"
echo '*****'
if [ -f "$1".tar.xz ]; then
create_empty
echo "Extracting..."
tar xp -C "$WORK" -f "$1".tar.xz
elif [ -f "$1" ]; then
# let tar determine the right format
create_empty
echo "Extracting..."
tar xp -C "$WORK" -f "$1"
elif [ -f "$1".qcow2 ]; then
cp -v "$1".qcow2 "$TMPIMG"
# mount
mkdir "$WORK"
"$QEMUSD" --daemonize --pidfile qemusd.$$.pid --blockdev "driver=qcow2,file.driver=file,file.filename=$TMPIMG,node-name=disk0" --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock --export type=nbd,id=exp0,node-name=disk0,name=disk0,writable=on
"$NBDCL" -unix /tmp/nbd.sock -N disk0 -b "$BLOCKSIZE" "$NBD"
sleep 1
mount "$NBD"p1 "$WORK"
else
echo "Could not find base for $1"
fi
# mount proc, sys, dev
mount -t proc proc "$WORK/proc"
mount -t sysfs sys "$WORK/sys"
mount -t devtmpfs udev "$WORK/dev"
mkdir -p "$WORK/dev/pts"
mount -t devpts devpts "$WORK/dev/pts"
# prevent service activation (will be deleted by finalize)
echo -e '#!/bin/sh\nexit 101' >"$WORK/usr/sbin/policy-rc.d"
chmod +x "$WORK/usr/sbin/policy-rc.d"
else
echo '*****'
echo "** Preparing new environment"
echo '*****'
create_empty
fi
}
run() {
chroot "$WORK" "$@"
}
finalize() {
echo '*****'
echo "** Generating disk image $1-$DATE"
echo '*****'
rm -f "$WORK/usr/sbin/policy-rc.d"
# erase those files only if not symlinks
for foo in /etc/machine-id /var/lib/dbus/machine-id; do
if [ -f "$WORK$foo" ] && [ ! -L "$WORK$foo" ]; then
rm -f "$WORK$foo"
fi
done
echo localhost >"$WORK/etc/hostname"
# generate /etc/shells-release file
cat >"${WORK}/etc/shells-release" <<EOF
# file automatically generated by Shells
SHELLS_IMAGE_TAG="$DATE"
SHELLS_IMAGE_CODE="$1"
SHELLS_IMAGE_TIMESTAMP="$(date +%s)"
EOF
# making sure we have no remaining process
fuser --kill --ismountpoint --mount "$WORK" && sleep 1 || true
# unmount all mounts under $WORK (in reverse order, deepest first)
grep " $WORK/" /proc/self/mounts | cut -d' ' -f2 | sort -r | while read mnt; do
umount "$mnt" 2>/dev/null || umount -l "$mnt" 2>/dev/null || true
done
# build squashfs image
mksquashfs "$WORK" "$1-$DATE.squashfs" -comp xz -noappend -progress
echo "Syncing..."
umount "$WORK"
"$NBDCL" -d "$NBD"
sleep 0.5
if [ -f qemusd.$$.pid ]; then
kill $(cat qemusd.$$.pid )
sleep 0.5
fi
"$QEMUIMG" convert -c -p -f qcow2 -O qcow2 "work$$.qcow2" "$1-$DATE.qcow2"
mv -f "work$$.qcow2" "$1.qcow2"
if [ ! -d rbdconv ]; then
# grab rbdconv
git clone https://github.com/Shells-com/rbdconv.git
fi
# need to convert to raw file first so that raw-to-rbd.php can get the filesize first
"$QEMUIMG" convert -f qcow2 -O raw "$1-$DATE.qcow2" "$1-$DATE.raw"
php rbdconv/raw-to-rbd.php "$1-$DATE.raw" | xz -z -9 -T $(nproc --ignore=4) -v >"$1-$DATE.shells"
rm -f "$1-$DATE.raw"
go run github.com/KarpelesLab/rest/cli/restupload@latest -api Shell/OS:uploadOfficialImage -params "blocksize=$BLOCKSIZE" "$1-$DATE.qcow2" "$1-$DATE.squashfs" "$1-$DATE.shells"
# complete, list the file
ls -la "$1-$DATE.qcow2"
}
add_firstrun() {
# add first run process before sysinit but after network
cp "$SCRIPTSDIR/firstrun.sh" "$WORK/.firstrun.sh"
chmod +x "$WORK/.firstrun.sh"
local AFTER="$1"
if [ x"$AFTER" = x ]; then
# can also be NetworkManager-wait-online.service
AFTER="network-online.target"
fi
if [ -d "$WORK/usr/lib/systemd/system" ]; then
# systemd method
cat >"$WORK/usr/lib/systemd/system/cloud-firstrun.service" <<EOF
[Unit]
Description=Cloud firstrun handler
ConditionFileIsExecutable=/.firstrun.sh
After=$AFTER
Wants=$AFTER
Before=network-online.target
Before=sshd-keygen.service
Before=sshd.service
Before=systemd-user-sessions.service
[Service]
Type=oneshot
ExecStart=/.firstrun.sh start
TimeoutSec=0
RemainAfterExit=yes
StandardOutput=journal+console
[Install]
WantedBy=sysinit.target
EOF
# enable
run systemctl enable cloud-firstrun
else
echo "No systemd found!"
exit 1
fi
}