-
-
Save morphis/abdc1e83ba0578e756073bd89fa128ed to your computer and use it in GitHub Desktop.
Create snap image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Copyright (C) 2016 Canonical Ltd | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License version 3 as | |
# published by the Free Software Foundation. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
set -ex | |
workdir=$(mktemp -d) | |
output= | |
kernel= | |
gadget= | |
model_assertion= | |
extra_snaps= | |
extra_devmode_snaps= | |
extra_assertions= | |
arch= | |
channel=stable | |
show_help() { | |
echo "Usage: $0 [OPTIONS]" | |
echo | |
echo "optional arguments:" | |
echo " --help: Show this help message and exit" | |
echo " --channel: Select another channel to use for build the image (default: $channel)" | |
echo " --kernel-snap: Kernel snap to use for building the boot image" | |
echo " --gadget-snap: Device gadget snap to use" | |
echo " --model-assertion: Model assertion file to use" | |
echo " --extra-snap: Additional snap to add to the created image. Value is directly passed to prepare-image" | |
echo " --extra-assertion: Additional assertion file to include in the image" | |
echo " --output: Target path and file name for the boot image to create" | |
echo " --arch: Target device architecture" | |
} | |
while [ -n "$1" ]; do | |
case "$1" in | |
--help) | |
show_help | |
exit | |
;; | |
--channel=*) | |
channel=${1#*=} | |
shift | |
;; | |
--kernel-snap=*) | |
kernel=${1#*=} | |
shift | |
;; | |
--gadget-snap=*) | |
gadget=${1#*=} | |
shift | |
;; | |
--output=*) | |
output=${1#*=} | |
shift | |
;; | |
--model-assertion=*) | |
model_assertion=${1#*=} | |
shift | |
;; | |
--extra-snap=*) | |
snap=${1#*=} | |
extra_snaps="$extra_snaps --extra-snaps $snap" | |
shift | |
;; | |
--extra-devmode-snap=*) | |
snap=${1#*=} | |
extra_devmode_snaps="$extra_devmode_snaps $snap" | |
shift | |
;; | |
--extra-assertion=*) | |
assert=${1#*=} | |
extra_assertions="$extra_assertions $assert" | |
shift | |
;; | |
--arch=*) | |
arch=${1#*=} | |
shift | |
;; | |
*) | |
echo "Unknown command: $1" | |
exit 1 | |
;; | |
esac | |
done | |
if [ -z "$kernel" ] || [ -z "$gadget" ] || [ -z "$model_assertion" ] ; then | |
echo "ERROR: Please provide a valid kernel and gadget snap and a model assertion" | |
exit 1 | |
fi | |
channel=stable | |
image_size=2G | |
image_name=ubuntu-core-mako | |
image_fs_label=writable | |
cp $kernel $workdir/mako-kernel.snap | |
cp $gadget $workdir/mako.snap | |
mkdir $workdir/rootfs | |
mkdir $workdir/rootfs/boot | |
snap prepare-image \ | |
--channel $channel \ | |
--extra-snaps $workdir/mako.snap \ | |
--extra-snaps $workdir/mako-kernel.snap \ | |
$extra_snaps \ | |
$model_assertion \ | |
$workdir/rootfs | |
sudo chown -R root:root $workdir/rootfs | |
mkdir $workdir/writable | |
mkdir $workdir/writable/system-data | |
cp -ra $workdir/rootfs/image/* $workdir/writable/system-data/ | |
# Migrate all systemd units from core snap into the writable area. This | |
# would be normally done on firstboot by the initramfs but we can't rely | |
# on that because we are adding another file in there and that will | |
# prevent the initramfs from transitioning any files. | |
core_snap=$(find $workdir/writable/system-data/var/lib/snapd/snaps -name "core_*.snap") | |
tmp_core=`mktemp -d` | |
sudo mount -o loop $core_snap $tmp_core | |
mkdir -p $workdir/writable/system-data/etc/systemd | |
cp -rav $tmp_core/etc/systemd/* \ | |
$workdir/writable/system-data/etc/systemd/ | |
sudo umount $tmp_core | |
rm -rf $tmp_core | |
# system-user assertion which gives us our ubuntu:ubuntu user we use to | |
# log into the system | |
if [ -n "$extra_assertions" ]; then | |
mkdir -p $workdir/writable/system-data/var/lib/snapd/seed/assertions | |
for assert in $extra_assertions ; do | |
cp $assert $workdir/writable/system-data/var/lib/snapd/seed/assertions/ | |
done | |
fi | |
# Use NetworkManager as our default network management solution | |
mkdir -p $workdir/writable/system-data/etc/netplan | |
cat << EOF > $workdir/writable/system-data/etc/netplan/00-default-nm-renderer.yaml | |
network: | |
renderer: NetworkManager | |
EOF | |
# Disable console-conf for the first boot | |
mkdir -p $workdir/writable/system-data/var/lib/console-conf/ | |
touch $workdir/writable/system-data/var/lib/console-conf/complete | |
# Create systemd service which is running on firstboot and sets up | |
# various things for us. | |
mkdir -p $workdir/writable/system-data/etc/systemd/system | |
cat << 'EOF' > $workdir/writable/system-data/etc/systemd/system/devmode-firstboot.service | |
[Unit] | |
Description=Run devmode firstboot setup | |
After=snapd.service snapd.socket | |
[Service] | |
Type=oneshot | |
ExecStart=/bin/bash -c "/bin/bash /writable/system-data/var/lib/devmode-firstboot/run.sh > /dev/console" | |
RemainAfterExit=yes | |
EOF | |
mkdir -p $workdir/writable/system-data/etc/systemd/system/multi-user.target.wants | |
ln -sf /etc/systemd/system/devmode-firstboot.service \ | |
$workdir/writable/system-data/etc/systemd/system/multi-user.target.wants/devmode-firstboot.service | |
mkdir $workdir/writable/system-data/var/lib/devmode-firstboot | |
cat << 'EOF' > $workdir/writable/system-data/var/lib/devmode-firstboot/run.sh | |
#!/bin/bash | |
set -ex | |
# Don't start again if we're already done | |
if [ -e /writable/system-data/var/lib/devmode-firstboot/complete ] ; then | |
exit 0 | |
fi | |
echo "Start devmode-firstboot $(date -Iseconds --utc)" | |
if [ "$(snap managed)" = "true" ]; then | |
echo "System already managed, exiting" | |
exit 0 | |
fi | |
# no changes at all | |
while ! snap changes ; do | |
echo "No changes yet, waiting" | |
sleep 1 | |
done | |
while snap changes | grep -qE '(Do|Doing) .*Initialize system state' ; do | |
echo "Initialize system state is in progress, waiting" | |
sleep 1 | |
done | |
if [ -n "$(snap known system-user)" ]; then | |
echo "Trying to create known user" | |
snap create-user --known --sudoer | |
fi | |
# Enable console-conf again | |
rm /writable/system-data/var/lib/console-conf/complete | |
# Mark us done | |
touch /writable/system-data/var/lib/devmode-firstboot/complete | |
# Reboot the system as its now prepared for the user | |
reboot | |
EOF | |
chmod +x $workdir/writable/system-data/var/lib/devmode-firstboot/run.sh | |
if [ -n "$extra_devmode_snaps" ]; then | |
mkdir -p $workdir/writable/system-data/var/lib/snapd/seed/snaps/ | |
for snap in $extra_devmode_snaps ; do | |
snap_name= | |
if [ -e $snap ]; then | |
cp $snap $workdir/writable/system-data/var/lib/snapd/seed/snaps/ | |
snap_name=`basename $snap .snap` | |
else | |
snap_name=`echo $snap | cut -d':' -f 1` | |
if [ -z "$snap_name" ]; then | |
echo "ERROR: no valid snap name provided '$snap'" | |
exit 1 | |
fi | |
snap_channel=`echo $snap | cut -d':' -f 2` | |
if [ -z "$snap_channel" ]; then | |
snap_channel=edge | |
fi | |
snap_url=`curl -H "X-Ubuntu-Series: 16" -H "X-Ubuntu-Architecture: $arch" https://search.apps.ubuntu.com/api/v1/snaps/details/$snap_name?channel=$snap_channel | jq .download_url` | |
wget $snap_url -O $workdir/writable/system-data/snapd/seed/snaps/$snap_name.snap | |
fi | |
name=`snap info $snap | grep name | awk '{print $2}'` | |
cat <<EOF >> $workdir/writable/system-data/var/lib/snapd/seed/seed.yaml | |
- name: $name | |
unasserted: true | |
devmode: true | |
file: $snap_name.snap | |
EOF | |
done | |
fi | |
(cd $workdir/writable ; tar cf $workdir/writable.tar *) | |
tar --numeric-owner --exclude=dev/ -tvvf $workdir/writable.tar \ | |
--directory $workdir > $workdir/writable.content | |
make_ext4fs -u / -U $workdir/writable.content -l $image_size -s \ | |
-L $image_fs_label $workdir/$image_name.img $workdir/writable | |
cp $workdir/$image_name.img $output | |
sudo rm -rf $workdir | |
0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment