Merge ~xueshengyao/pc-enablement/+git/oem-scripts:master into ~oem-solutions-engineers/pc-enablement/+git/oem-scripts:master

Proposed by Shengyao Xue
Status: Merged
Merged at revision: a8558fa198690dc2b059e269086ba9c012295092
Proposed branch: ~xueshengyao/pc-enablement/+git/oem-scripts:master
Merge into: ~oem-solutions-engineers/pc-enablement/+git/oem-scripts:master
Diff against target: 373 lines (+331/-0)
5 files modified
autoISO.go (+321/-0)
debian/changelog (+6/-0)
debian/control (+1/-0)
debian/install (+1/-0)
debian/rules (+2/-0)
Reviewer Review Type Date Requested Status
jeremyszu Pending
Shih-Yuan Lee Pending
Review via email: mp+407436@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/autoISO.go b/autoISO.go
2new file mode 100644
3index 0000000..3f7eb72
4--- /dev/null
5+++ b/autoISO.go
6@@ -0,0 +1,321 @@
7+// make a auto install OEM ISO from a base OEM ISO image.
8+// Usage: autoISO /path/to/oem-xxx.iso
9+// Copyright (C) 2021 Canonical Ltd.
10+// Author: Shengyao Xue <shengyao.xue@canonical.com>
11+//
12+// This program is free software; you can redistribute it and/or modify
13+// it under the terms of the GNU General Public License as published by
14+// the Free Software Foundation; either version 3 of the License, or
15+// (at your option) any later version.
16+//
17+// This program is distributed in the hope that it will be useful,
18+// but WITHOUT ANY WARRANTY; without even the implied warranty of
19+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+// GNU General Public License for more details.
21+//
22+// You should have received a copy of the GNU General Public License
23+// along with this program; if not, write to the Free Software
24+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25+
26+package main
27+
28+import (
29+ "bytes"
30+ "flag"
31+ "fmt"
32+ "io/ioutil"
33+ "os"
34+ "os/exec"
35+ "os/user"
36+ "path/filepath"
37+)
38+
39+func check(e error) {
40+ if e != nil {
41+ panic(e)
42+ }
43+}
44+
45+func fileExists(path string) bool {
46+ _, err := os.Stat(path)
47+ return err == nil
48+}
49+
50+func main() {
51+ if !fileExists("/usr/bin/mksquashfs") {
52+ fmt.Println("Please install squashfs-tools package first.")
53+ os.Exit(-1)
54+ }
55+ if !fileExists("/usr/bin/genisoimage") {
56+ fmt.Println("Please install genisoimage package first.")
57+ os.Exit(-1)
58+ }
59+
60+ extractOnly := flag.Bool("x", false, "extract the base ISO image only.")
61+ keepFolder := flag.Bool("k", false, "keep the temporary folder after the new image created.")
62+ sanityTest := flag.Bool("s", false, "add first boot sanity test.")
63+ flag.Parse()
64+
65+ currentUser, err := user.Current()
66+ check(err)
67+ if currentUser.Username != "root" {
68+ fmt.Printf("This program requires superuser privileges, please run it as root.\n")
69+ os.Exit(-1)
70+ }
71+ var baseiso string
72+ if flag.NArg() == 1 {
73+ baseiso = filepath.Clean(flag.Arg(0))
74+ } else {
75+ fmt.Printf("Usage: autoISO [option] /path/to/oem-xxx.iso\n")
76+ fmt.Printf(" -h: help for options.\n")
77+ os.Exit(0)
78+ }
79+
80+ parentDir, err := os.Getwd()
81+ check(err)
82+ fmt.Printf("autoISO started, the artifacts will be created in current working directory: %v\n", parentDir)
83+ fmt.Printf("This might take several minutes. Please wait...\n")
84+ //autoISODir, err := os.MkdirTemp(parentDir, "autoISO-*")
85+ autoISODir, err := ioutil.TempDir(parentDir, "autoISO-*")
86+ check(err)
87+ check(os.Chdir(autoISODir))
88+ check(os.Mkdir("iso", 0775))
89+ check(os.Mkdir("squash", 0775))
90+ cmd := exec.Command("mount", baseiso, "iso")
91+ cmd.Dir = autoISODir
92+ check(cmd.Run())
93+ cmd = exec.Command("mount", "iso/casper/filesystem.squashfs", "squash")
94+ check(cmd.Run())
95+ cmd = exec.Command("cp", "-a", "iso", "isorw")
96+ check(cmd.Run())
97+ cmd = exec.Command("cp", "-a", "squash", "squashrw")
98+ check(cmd.Run())
99+ cmd = exec.Command("umount", "squash")
100+ check(cmd.Run())
101+ cmd = exec.Command("umount", "iso")
102+ check(cmd.Run())
103+ if *extractOnly {
104+ fmt.Printf("autoISO extracted only.\n")
105+ } else {
106+ // oem-config
107+ check(os.Mkdir("squashrw/usr/lib/oem-config/pre-install", 0775))
108+ preseed := `#!/bin/bash
109+cat <<EOF | sudo debconf-communicate ubiquity
110+SET passwd/user-fullname u
111+FSET passwd/user-fullname seen true
112+SET passwd/username u
113+FSET passwd/username seen true
114+SET passwd/user-password u
115+FSET passwd/user-password seen true
116+SET passwd/user-password-again u
117+FSET passwd/user-password-again seen true
118+SET passwd/auto-login true
119+FSET passwd/auto-login seen true
120+SET time/zone Asia/Shanghai
121+FSET time/zone seen true
122+EOF
123+
124+cat <<EOF | sudo debconf-communicate keyboard-configuration
125+SET keyboard-configuration/xkb-keymap us
126+FSET keyboard-configuration/xkb-keymap seen true
127+SET keyboard-configuration/layoutcode us
128+FSET keyboard-configuration/layoutcode seen true
129+SET keyboard-configuration/layout English (US)
130+FSET keyboard-configuration/layout seen true
131+SET keyboard-configuration/variant English (US)
132+FSET keyboard-configuration/variant seen true
133+EOF
134+`
135+ //check(ioutil.WriteFile("squashrw/usr/lib/oem-config/pre-install/oobe-preseed", []byte(preseed), 0775))
136+ check(ioutil.WriteFile("squashrw/usr/lib/oem-config/pre-install/oobe-preseed", []byte(preseed), 0775))
137+ grub := "GRUB_CMDLINE_LINUX=$(echo $GRUB_CMDLINE_LINUX automatic-oem-config)\n"
138+ check(ioutil.WriteFile("squashrw/etc/default/grub.d/automatic-oem-config.cfg", []byte(grub), 0664))
139+
140+ // sanity test
141+ if *sanityTest {
142+ oemDevFirstBoot := `#!/bin/bash
143+
144+set -x
145+
146+while true ; do
147+ sleep 10
148+ ping -c 3 8.8.8.8 && break # ideally wired network works, use it.
149+ sleep 10
150+ if [ -e /etc/oem-config-hack/connect-wifi ]; then
151+ bash /etc/oem-config-hack/connect-wifi
152+ else
153+ echo Wired network not working and wifi not available, Quit!
154+ bash
155+ exit
156+ fi
157+done
158+
159+if ! dpkg-query -W prepare-checkbox-sanity; then
160+ sudo add-apt-repository -y ppa:checkbox-dev/ppa
161+ sudo apt install -y prepare-checkbox-sanity
162+ sudo reboot
163+ exit
164+fi
165+
166+if [ -e ~/.config/autostart/oem-dev-firstboot.desktop ]; then
167+ rm ~/.config/autostart/oem-dev-firstboot.desktop
168+fi
169+
170+checkbox-run-plan pc-sanity-smoke-test --checkbox-conf /home/u/.config/checkbox.conf -b
171+
172+sleep 3
173+
174+gio open ~/.local/share/checkbox-ng/submission_*.html
175+
176+bash
177+`
178+ check(ioutil.WriteFile("squashrw/usr/bin/oem-dev-firstboot", []byte(oemDevFirstBoot), 0775))
179+ oemDevFirstBootAutoStart := `#!/bin/bash
180+set -x
181+mkdir -p "/home/$1/.config/autostart/"
182+cat > /home/$1/.config/autostart/oem-dev-firstboot.desktop << EOF
183+[Desktop Entry]
184+Version=1.0
185+Encoding=UTF-8
186+Name=Local Sanity
187+Type=Application
188+Terminal=true
189+Exec=/usr/bin/oem-dev-firstboot
190+Categories=System;Settings
191+EOF
192+cat > /home/$1/.config/checkbox.conf <<EOF
193+[environment]
194+ROUTERS = multiple
195+OPEN_N_SSID = ubuntu-cert-n-open
196+OPEN_BG_SSID = ubuntu-cert-bg-open
197+OPEN_AC_SSID = ubuntu-cert-ac-open
198+OPEN_AX_SSID = ubuntu-cert-ax-open
199+WPA_N_SSID = ubuntu-cert-n-wpa
200+WPA_BG_SSID = ubuntu-cert-bg-wpa
201+WPA_AC_SSID = ubuntu-cert-ac-wpa
202+WPA_AX_SSID = ubuntu-cert-ax-wpa
203+WPA_N_PSK = insecure
204+WPA_BG_PSK = insecure
205+WPA_AC_PSK = insecure
206+WPA_AX_PSK = insecure
207+SERVER_IPERF = 192.168.1.99
208+TEST_TARGET_IPERF = 192.168.1.99
209+BTDEVADDR = 34:13:E8:9A:52:12
210+
211+# Transfer server
212+TRANSFER_SERVER = cdimage.ubuntu.com
213+EOF
214+touch "/home/$1/.config/gnome-initial-setup-done"
215+chown -R "$1.$1" "/home/u/.config"
216+`
217+ check(ioutil.WriteFile("squashrw/usr/bin/oem-dev-firstboot-autostart", []byte(oemDevFirstBootAutoStart), 0775))
218+ oemDevFirstBootPostInstall := `#!/bin/bash
219+set -x
220+/usr/bin/oem-dev-firstboot-autostart u
221+`
222+ check(ioutil.WriteFile("squashrw/usr/lib/oem-config/post-install/oem-dev-firstboot", []byte(oemDevFirstBootPostInstall), 0775))
223+ }
224+ // ubiquity
225+ ubiquity, err := ioutil.ReadFile("squashrw/usr/lib/ubiquity/bin/ubiquity")
226+ check(err)
227+ ubiquity = bytes.Replace(ubiquity, []byte("def run_oem_hooks():\n \"\"\"Run hook scripts from /usr/lib/oem-config/post-install.\"\"\"\n hookdir = '/usr/lib/oem-config/post-install'\n"), []byte("def run_oem_hooks(hookdir):\n \"\"\"Run hook scripts from hookdir.\"\"\""), -1)
228+ ubiquity = bytes.Replace(ubiquity, []byte("if oem_config:\n run_oem_hooks()"), []byte("if oem_config:\n run_oem_hooks('/usr/lib/oem-config/post-install')"), -1)
229+ ubiquity = bytes.Replace(ubiquity, []byte("if args"), []byte("if oem_config:\n run_oem_hooks('/usr/lib/oem-config/pre-install')\n\n if args"), -1)
230+ check(ioutil.WriteFile("squashrw/usr/lib/ubiquity/bin/ubiquity", ubiquity, 0755))
231+
232+ // recovery
233+ recovery, err := ioutil.ReadFile("squashrw/usr/lib/ubiquity/plugins/ubuntu-recovery.py")
234+ check(err)
235+ // check if this change already landed to ubuntu-recovery package (version >= 0.4.9~20.04ouagadougou22)
236+ if !bytes.Contains(recovery, []byte("'UBIQUITY_AUTOMATIC' in os.environ")) {
237+ recovery = bytes.Replace(recovery, []byte("os.path.exists(\"/cdrom/.oem/bypass_create_media\")"), []byte("os.path.exists(\"/cdrom/.oem/bypass_create_media\") or ('UBIQUITY_AUTOMATIC' in os.environ)"), -1)
238+ check(ioutil.WriteFile("squashrw/usr/lib/ubiquity/plugins/ubuntu-recovery.py", recovery, 0755))
239+ }
240+
241+ // bootstrap
242+ bootstrap, err := ioutil.ReadFile("squashrw/usr/lib/ubiquity/plugins/ubuntu-bootstrap.py")
243+ check(err)
244+ bootstrap = bytes.Replace(bootstrap, []byte("gi.require_version('UDisks', '2.0')\n"), []byte("gi.require_version('UDisks', '2.0')\nfrom gi.repository import GLib\n"), -1)
245+ bootstrap = bytes.Replace(bootstrap, []byte("self.interactive_recovery.set_sensitive(False)\n self.automated_recovery.set_sensitive(False)"), []byte("self.interactive_recovery.set_sensitive(False)\n self.automated_recovery.set_sensitive(False)\n if value == \"dev\" and stage == 1:\n self.automated_recovery.set_active(True)\n self.controller.allow_go_forward(True)\n GLib.timeout_add(5000, self.controller.go_forward)\n"), -1)
246+ bootstrap = bytes.Replace(bootstrap, []byte("elif rec_type == 'hdd' or rec_type == 'dev':"), []byte("elif rec_type == 'hdd' or (rec_type == 'dev' and self.stage == 2):"), -1)
247+ bootstrap = bytes.Replace(bootstrap, []byte("or rec_type == 'hdd' or rec_type == 'dev':"), []byte("or rec_type == 'hdd' or (rec_type == 'dev' and self.stage == 2):"), -1)
248+ bootstrap = bytes.Replace(bootstrap, []byte("rpconf.rec_type == \"factory\""), []byte("(rpconf.rec_type == \"factory\" or rpconf.rec_type == \"dev\")"), -1)
249+ check(ioutil.WriteFile("squashrw/usr/lib/ubiquity/plugins/ubuntu-bootstrap.py", bootstrap, 0755))
250+
251+ // user ubuntu, reservation for MAAS, cloud init etc.
252+ uUbuntu := `#!/bin/bash
253+adduser --disabled-password --gecos "" ubuntu
254+adduser ubuntu sudo
255+`
256+ check(ioutil.WriteFile("squashrw/usr/lib/oem-config/post-install/u-ubuntu", []byte(uUbuntu), 0775))
257+
258+ // gconf-modification
259+ gconfModification := `#!/bin/bash
260+cat <<EOF >> /usr/share/glib-2.0/schemas/certification.gschema.override
261+[org.gnome.settings-daemon.plugins.power]
262+idle-dim=false
263+#sleep-display-ac=0
264+sleep-inactive-ac-timeout=0
265+sleep-inactive-battery-timeout=0
266+[org.gnome.desktop.session]
267+idle-delay=0
268+[org.gnome.desktop.screensaver]
269+ubuntu-lock-on-suspend=false
270+lock-enabled=false
271+idle-activation-enabled=false
272+EOF
273+
274+glib-compile-schemas /usr/share/glib-2.0/schemas
275+`
276+ check(ioutil.WriteFile("squashrw/usr/lib/oem-config/post-install/gconf-modification", []byte(gconfModification), 0775))
277+
278+ // disable unattended update of APT
279+ oemDisableUattn := `#!/usr/bin/python3
280+import softwareproperties
281+from softwareproperties import SoftwareProperties
282+import os
283+
284+# given
285+# euid,eguid 1000,1000
286+# ruid,rguid 0, 0
287+# we need to seteuid to 0 so we have permission.
288+os.seteuid(0)
289+os.setegid(0)
290+
291+s = SoftwareProperties.SoftwareProperties()
292+s.set_update_automation_level(softwareproperties.UPDATE_MANUAL)
293+
294+print("OK")
295+`
296+ check(ioutil.WriteFile("squashrw/usr/lib/oem-config/post-install/oem-disable-uattn", []byte(oemDisableUattn), 0775))
297+
298+ // sudoers
299+ sudoers := "%sudo ALL=(ALL:ALL) NOPASSWD: ALL\n"
300+ check(ioutil.WriteFile("squashrw/etc/sudoers.d/oem-config-hack-nopwd", []byte(sudoers), 0664))
301+
302+ // make new squashfs
303+ cmd = exec.Command("mksquashfs", "squashrw", "isorw/casper/filesystem.squashfs", "-noappend")
304+ check(cmd.Run())
305+
306+ // projectCfg
307+ projectCfg, err := ioutil.ReadFile("isorw/preseed/project.cfg")
308+ check(err)
309+ // change recovery_type to dev
310+ projectCfg = bytes.Replace(projectCfg, []byte("# Hide"), []byte("ubiquity ubuntu-recovery/recovery_type string dev\n\n# Hide"), -1)
311+ // change poweroff to reboot
312+ projectCfg = bytes.Replace(projectCfg, []byte("ubiquity/reboot boolean false"), []byte("ubiquity/reboot boolean true"), -1)
313+ projectCfg = bytes.Replace(projectCfg, []byte("ubiquity/poweroff boolean true"), []byte("ubiquity/poweroff boolean false"), -1)
314+ check(ioutil.WriteFile("isorw/preseed/project.cfg", projectCfg, 0755))
315+
316+ // make new ISO
317+ cmd = exec.Command("genisoimage", "-J", "-l", "-cache-inodes", "-allow-multidot", "-r", "-input-charset", "utf-8", "-eltorito-alt-boot", "-efi-boot", "boot/grub/efi.img", "-no-emul-boot", "-o", parentDir+"/"+filepath.Base(baseiso)+"."+filepath.Base(autoISODir)+".iso", "isorw")
318+ check(cmd.Run())
319+
320+ if !*keepFolder {
321+ check(os.RemoveAll(autoISODir))
322+ fmt.Printf("autoISO done.\n")
323+ } else {
324+ fmt.Printf("autoISO done. Temporary folder %v keeped.\n", autoISODir)
325+ }
326+ }
327+}
328diff --git a/debian/changelog b/debian/changelog
329index 38037d5..049e0a6 100644
330--- a/debian/changelog
331+++ b/debian/changelog
332@@ -1,3 +1,9 @@
333+oem-scripts (1.9) focal; urgency=medium
334+
335+ * Add autoISO.go to oem-scripts.
336+
337+ -- Shengyao Xue <shengyao.xue@canonical.com> Fri, 20 Aug 2021 16:04:49 +0800
338+
339 oem-scripts (1.8) focal; urgency=medium
340
341 * debian/tests/mir-bug,
342diff --git a/debian/control b/debian/control
343index 7ef7aa5..2427bba 100644
344--- a/debian/control
345+++ b/debian/control
346@@ -6,6 +6,7 @@ Build-Depends:
347 debhelper (>=11),
348 dh-python,
349 flake8,
350+ golang-go,
351 python3-all,
352 python3-debian,
353 python3-launchpadlib,
354diff --git a/debian/install b/debian/install
355new file mode 100644
356index 0000000..b1f5851
357--- /dev/null
358+++ b/debian/install
359@@ -0,0 +1 @@
360+autoISO /usr/sbin/
361diff --git a/debian/rules b/debian/rules
362index 98284ec..02ab8ad 100755
363--- a/debian/rules
364+++ b/debian/rules
365@@ -3,6 +3,8 @@
366
367 %:
368 dh $@ --with python3 --buildsystem=pybuild
369+ go build autoISO.go
370+ strip autoISO
371
372 override_dh_auto_test:
373 ./tests/test_black

Subscribers

People subscribed via source and target branches