Merge lp:~rsalveti/ubuntu-system-image/production-factory-reset into lp:~registry/ubuntu-system-image/client

Proposed by Ricardo Salveti
Status: Merged
Merged at revision: 310
Proposed branch: lp:~rsalveti/ubuntu-system-image/production-factory-reset
Merge into: lp:~registry/ubuntu-system-image/client
Diff against target: 227 lines (+98/-4)
9 files modified
NEWS.rst (+2/-0)
dbus-manpage.rst (+7/-0)
systemimage/api.py (+3/-0)
systemimage/apply.py (+7/-2)
systemimage/dbus.py (+8/-0)
systemimage/main.py (+8/-2)
systemimage/tests/test_api.py (+14/-0)
systemimage/tests/test_dbus.py (+24/-0)
systemimage/tests/test_main.py (+25/-0)
To merge this branch: bzr merge lp:~rsalveti/ubuntu-system-image/production-factory-reset
Reviewer Review Type Date Requested Status
Barry Warsaw (community) Approve
Review via email: mp+248988@code.launchpad.net

Commit message

Adding support for production factory reset

Description of the change

Adding support for production factory reset

To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :

Other than the one comment, LGTM! Thanks. I will merge and test.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.rst'
2--- NEWS.rst 2015-02-05 02:49:43 +0000
3+++ NEWS.rst 2015-02-07 02:56:01 +0000
4@@ -44,6 +44,8 @@
5 * As part of LP: #1417176, the ``--no-reboot`` switch for
6 ``system-image-cli(1)`` has been deprecated. Use ``--no-apply`` instead
7 (``-g`` is still the shortcut).
8+ * Support production factory resets. `system-image-cli --production-reset`
9+ and a new D-Bus API method `ProductionReset()` are added. (LP: #1419027)
10
11 2.5.1 (2014-10-21)
12 ==================
13
14=== modified file 'dbus-manpage.rst'
15--- dbus-manpage.rst 2015-02-05 00:48:59 +0000
16+++ dbus-manpage.rst 2015-02-07 02:56:01 +0000
17@@ -161,6 +161,13 @@
18
19 *New in system-image 2.3*.
20
21+``ProductionReset()``
22+ This is a **synchronous** call which wipes the data partition, sets a flag
23+ for factory wipe (used in production), and issue a reboot to recovery.
24+ A ``Rebooting`` signal may be sent, depending on timing.
25+
26+ *New in system-image 3.0*.
27+
28 ``SetSetting(key, value)``
29 This is a **synchronous** call to write or update a setting. ``key`` and
30 ``value`` are strings. While any key/value pair may be set, some keys
31
32=== modified file 'systemimage/api.py'
33--- systemimage/api.py 2015-02-05 00:48:59 +0000
34+++ systemimage/api.py 2015-02-07 02:56:01 +0000
35@@ -121,3 +121,6 @@
36
37 def factory_reset(self):
38 factory_reset()
39+
40+ def production_reset(self):
41+ factory_reset(True)
42
43=== modified file 'systemimage/apply.py'
44--- systemimage/apply.py 2015-02-05 00:48:59 +0000
45+++ systemimage/apply.py 2015-02-07 02:56:01 +0000
46@@ -63,11 +63,16 @@
47 pass
48
49
50-def factory_reset():
51+def factory_reset(production_reset=False):
52 """Perform a factory reset."""
53 command_file = os.path.join(
54 config.updater.cache_partition, 'ubuntu_command')
55 with atomic(command_file) as fp:
56 print('format data', file=fp)
57- log.info('Performing a factory reset')
58+ if production_reset:
59+ print('enable factory_wipe', file=fp)
60+ if production_reset:
61+ log.info('Performing a production factory reset')
62+ else:
63+ log.info('Performing a factory reset')
64 config.hooks.apply().apply()
65
66=== modified file 'systemimage/dbus.py'
67--- systemimage/dbus.py 2015-02-05 00:48:59 +0000
68+++ systemimage/dbus.py 2015-02-07 02:56:01 +0000
69@@ -390,6 +390,14 @@
70
71 @log_and_exit
72 @method('com.canonical.SystemImage')
73+ def ProductionReset(self):
74+ self._api.production_reset()
75+ # This code may or may not run. We're racing against the system
76+ # reboot procedure.
77+ self.Rebooting(True)
78+
79+ @log_and_exit
80+ @method('com.canonical.SystemImage')
81 def Exit(self):
82 """Quit the daemon immediately."""
83 self.loop.quit()
84
85=== modified file 'systemimage/main.py'
86--- systemimage/main.py 2015-02-05 00:48:59 +0000
87+++ systemimage/main.py 2015-02-07 02:56:01 +0000
88@@ -109,6 +109,12 @@
89 help="""Perform a destructive factory reset and
90 reboot. WARNING: this will wipe all user data
91 on the device!""")
92+ parser.add_argument('--production-reset',
93+ default=False, action='store_true',
94+ help="""Perform a destructive production reset
95+ (similar to factory reset) and reboot.
96+ WARNING: this will wipe all user data
97+ on the device!""")
98 parser.add_argument('--switch',
99 default=None, action='store', metavar='CHANNEL',
100 help="""Switch to the given channel. This is
101@@ -155,8 +161,8 @@
102 config.skip_gpg_verification = True
103
104 # Perform a factory reset.
105- if args.factory_reset:
106- factory_reset()
107+ if args.factory_reset or args.production_reset:
108+ factory_reset(args.production_reset)
109 # We should never get here, except possibly during the testing
110 # process, so just return as normal.
111 return 0
112
113=== modified file 'systemimage/tests/test_api.py'
114--- systemimage/tests/test_api.py 2015-02-05 00:48:59 +0000
115+++ systemimage/tests/test_api.py 2015-02-07 02:56:01 +0000
116@@ -205,6 +205,20 @@
117 """))
118
119 @configuration
120+ def test_production_reset(self):
121+ mediator = Mediator()
122+ with patch('systemimage.apply.Reboot.apply') as mock:
123+ mediator.production_reset()
124+ self.assertTrue(mock.called)
125+ path = Path(config.updater.cache_partition) / 'ubuntu_command'
126+ with path.open('r', encoding='utf-8') as fp:
127+ command = fp.read()
128+ self.assertMultiLineEqual(command, dedent("""\
129+ format data
130+ enable factory_wipe
131+ """))
132+
133+ @configuration
134 def test_cancel(self):
135 # When we get to the step of downloading the files, cancel it.
136 self._setup_server_keyrings()
137
138=== modified file 'systemimage/tests/test_dbus.py'
139--- systemimage/tests/test_dbus.py 2015-02-05 02:49:43 +0000
140+++ systemimage/tests/test_dbus.py 2015-02-07 02:56:01 +0000
141@@ -23,6 +23,7 @@
142 'TestDBusDownload',
143 'TestDBusDownloadBigFiles',
144 'TestDBusFactoryReset',
145+ 'TestDBusProductionReset',
146 'TestDBusGetSet',
147 'TestDBusInfo',
148 'TestDBusMiscellaneous',
149@@ -55,6 +56,7 @@
150 from dbus.exceptions import DBusException
151 from functools import partial
152 from pathlib import Path
153+from textwrap import dedent
154 from systemimage.config import Configuration
155 from systemimage.helpers import MiB, safe_remove
156 from systemimage.reactor import Reactor
157@@ -1577,6 +1579,28 @@
158 self.assertEqual(command, 'format data\n')
159
160
161+class TestDBusProductionReset(_LiveTesting):
162+ def test_production_reset(self):
163+ # A production factory reset is applied.
164+ command_file = os.path.join(
165+ self.config.updater.cache_partition, 'ubuntu_command')
166+ self.assertFalse(os.path.exists(self.reboot_log))
167+ self.assertFalse(os.path.exists(command_file))
168+ reactor = SignalCapturingReactor('Rebooting')
169+ reactor.run(self.iface.ProductionReset)
170+ self.assertEqual(len(reactor.signals), 1)
171+ self.assertTrue(reactor.signals[0])
172+ with open(self.reboot_log, encoding='utf-8') as fp:
173+ reboot = fp.read()
174+ self.assertEqual(reboot, '/sbin/reboot -f recovery')
175+ with open(command_file, encoding='utf-8') as fp:
176+ command = fp.read()
177+ self.assertMultiLineEqual(command, dedent("""\
178+ format data
179+ enable factory_wipe
180+ """))
181+
182+
183 class TestDBusProgress(_LiveTesting):
184 def test_progress(self):
185 self.download_manually()
186
187=== modified file 'systemimage/tests/test_main.py'
188--- systemimage/tests/test_main.py 2015-02-05 00:48:59 +0000
189+++ systemimage/tests/test_main.py 2015-02-07 02:56:01 +0000
190@@ -18,6 +18,7 @@
191 __all__ = [
192 'TestCLIDuplicateDestinations',
193 'TestCLIFactoryReset',
194+ 'TestCLIProductionReset',
195 'TestCLIFilters',
196 'TestCLIListChannels',
197 'TestCLIMain',
198@@ -1016,6 +1017,30 @@
199 """))
200
201
202+class TestCLIProductionReset(unittest.TestCase):
203+ """Test the --production-reset option for production factory resets."""
204+
205+ @configuration
206+ def test_production_reset(self, config_d):
207+ # system-image-cli --production-reset
208+ capture = StringIO()
209+ with ExitStack() as resources:
210+ resources.enter_context(capture_print(capture))
211+ mock = resources.enter_context(
212+ patch('systemimage.apply.Reboot.apply'))
213+ resources.enter_context(argv('-C', config_d, '--production-reset'))
214+ cli_main()
215+ # A reboot was issued.
216+ self.assertTrue(mock.called)
217+ path = os.path.join(config.updater.cache_partition, 'ubuntu_command')
218+ with open(path, 'r', encoding='utf-8') as fp:
219+ command = fp.read()
220+ self.assertMultiLineEqual(command, dedent("""\
221+ format data
222+ enable factory_wipe
223+ """))
224+
225+
226 class TestCLISettings(unittest.TestCase):
227 """Test settings command line options."""
228

Subscribers

People subscribed via source and target branches