Merge ~xueshengyao/pc-enablement/+git/oem-scripts:master into ~oem-solutions-engineers/pc-enablement/+git/oem-scripts:master
- Git
- lp:~xueshengyao/pc-enablement/+git/oem-scripts
- master
- Merge into 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) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
jeremyszu | Pending | ||
Shih-Yuan Lee | Pending | ||
Review via email:
|
Commit message
Description of the change
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
1 | diff --git a/autoISO.go b/autoISO.go |
2 | new file mode 100644 |
3 | index 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 | +} |
328 | diff --git a/debian/changelog b/debian/changelog |
329 | index 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, |
342 | diff --git a/debian/control b/debian/control |
343 | index 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, |
354 | diff --git a/debian/install b/debian/install |
355 | new file mode 100644 |
356 | index 0000000..b1f5851 |
357 | --- /dev/null |
358 | +++ b/debian/install |
359 | @@ -0,0 +1 @@ |
360 | +autoISO /usr/sbin/ |
361 | diff --git a/debian/rules b/debian/rules |
362 | index 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 |