Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: client/common_lib/chromiumos_updater.py

Issue 3257003: Cleanups to test updater code. Handle service restart better, copy update-engine logs after tests. (Closed) Base URL: http://git.chromium.org/git/autotest.git
Patch Set: revert update if statefuldev fails Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « client/bin/site_sysinfo.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import httplib 5 import httplib
6 import logging 6 import logging
7 import re 7 import re
8 import socket 8 import socket
9 import urlparse 9 import urlparse
10 10
11 from autotest_lib.client.bin import chromeos_constants
11 from autotest_lib.client.common_lib import error 12 from autotest_lib.client.common_lib import error
12 13
13 STATEFULDEV_UPDATER = '/usr/local/bin/stateful_update' 14 STATEFULDEV_UPDATER = '/usr/local/bin/stateful_update'
14 UPDATER_BIN = '/usr/bin/update_engine_client' 15 UPDATER_BIN = '/usr/bin/update_engine_client'
15 UPDATER_IDLE = 'UPDATE_STATUS_IDLE' 16 UPDATER_IDLE = 'UPDATE_STATUS_IDLE'
16 UPDATER_NEED_REBOOT = 'UPDATE_STATUS_UPDATED_NEED_REBOOT' 17 UPDATER_NEED_REBOOT = 'UPDATE_STATUS_UPDATED_NEED_REBOOT'
17 18
18 19
19 class ChromiumOSError(error.InstallError): 20 class ChromiumOSError(error.InstallError):
20 """Generic error for ChromiumOS-specific exceptions.""" 21 """Generic error for ChromiumOS-specific exceptions."""
(...skipping 14 matching lines...) Expand all
35 36
36 37
37 def check_update_status(self): 38 def check_update_status(self):
38 update_status_cmd = ' '.join([UPDATER_BIN, '-status', '2>&1', 39 update_status_cmd = ' '.join([UPDATER_BIN, '-status', '2>&1',
39 '| grep CURRENT_OP']) 40 '| grep CURRENT_OP'])
40 update_status = self._run(update_status_cmd) 41 update_status = self._run(update_status_cmd)
41 return update_status.stdout.strip().split('=')[-1] 42 return update_status.stdout.strip().split('=')[-1]
42 43
43 44
44 def reset_update_engine(self): 45 def reset_update_engine(self):
45 self._run('initctl stop update-engine') 46 logging.info('Resetting update-engine.')
46 self._run('rm -f /tmp/update_engine_autoupdate_completed') 47 self._run('rm -f /tmp/update_engine_autoupdate_completed')
48 try:
49 self._run('initctl stop update-engine')
50 except error.AutoservRunError, e:
51 logging.warn('Stopping update-engine service failed. Already dead?')
47 self._run('initctl start update-engine') 52 self._run('initctl start update-engine')
48 # May need to wait if service becomes slow to restart. 53 # May need to wait if service becomes slow to restart.
49 if self.check_update_status() != UPDATER_IDLE: 54 if self.check_update_status() != UPDATER_IDLE:
50 raise ChromiumOSError('%s is not in an installable state' % 55 raise ChromiumOSError('%s is not in an installable state' %
51 self.host.hostname) 56 self.host.hostname)
52 57
53 58
54 def _run(self, cmd, *args, **kwargs): 59 def _run(self, cmd, *args, **kwargs):
55 return self.host.run(cmd, *args, **kwargs) 60 return self.host.run(cmd, *args, **kwargs)
56 61
57 62
63 def rootdev(self):
64 return self._run('rootdev').stdout.strip()
65
66
67 def revert_boot_partition(self):
68 part = self.rootdev()
69 logging.warn('Reverting update; Boot partition will be %s', part)
70 return self._run('/postinst %s 2>&1' % part)
71
72
58 def run_update(self): 73 def run_update(self):
59 # TODO(seano): Retrieve update_engine.log from target host.
60 if not self.update_url: 74 if not self.update_url:
61 return False 75 return False
62 76
63 # Check that devserver is accepting connections (from autoserv's host) 77 # Check that devserver is accepting connections (from autoserv's host)
64 # If we can't talk to it, the machine host probably can't either. 78 # If we can't talk to it, the machine host probably can't either.
65 auserver_host = urlparse.urlparse(self.update_url)[1] 79 auserver_host = urlparse.urlparse(self.update_url)[1]
66 try: 80 try:
67 httplib.HTTPConnection(auserver_host).connect() 81 httplib.HTTPConnection(auserver_host).connect()
68 except socket.error: 82 except socket.error:
69 raise ChromiumOSError('Update server at %s not available' % 83 raise ChromiumOSError('Update server at %s not available' %
70 auserver_host) 84 auserver_host)
71 85
72 logging.info('Installing from %s to: %s' % (self.update_url, 86 logging.info('Installing from %s to: %s' % (self.update_url,
73 self.host.hostname)) 87 self.host.hostname))
74 # If we find the system an updated-but-not-rebooted state, 88 # Reset update_engine's state & check that update_engine is idle.
75 # that's probably bad and we shouldn't trust that the previous 89 self.reset_update_engine()
76 # update left the machine in a good state. Reset update_engine's
77 # state & ensure that update_engine is idle.
78 if self.check_update_status() != UPDATER_IDLE:
79 self.reset_update_engine()
80 90
81 # Run autoupdate command. This tells the autoupdate process on 91 # Run autoupdate command. This tells the autoupdate process on
82 # the host to look for an update at a specific URL and version 92 # the host to look for an update at a specific URL and version
83 # string. 93 # string.
84 autoupdate_cmd = ' '.join([UPDATER_BIN, 94 autoupdate_cmd = ' '.join([UPDATER_BIN,
85 '--update', 95 '--update',
86 '--omaha_url=%s' % self.update_url, 96 '--omaha_url=%s' % self.update_url,
87 '--app_version ForcedUpdate',
88 ' 2>&1']) 97 ' 2>&1'])
89 logging.info(autoupdate_cmd) 98 logging.info(autoupdate_cmd)
90 try: 99 try:
91 self._run(autoupdate_cmd, timeout=900) 100 self._run(autoupdate_cmd, timeout=900)
92 except error.AutoservRunError, e: 101 except error.AutoservRunError, e:
93 # Either a runtime error occurred on the host, or 102 # Either a runtime error occurred on the host, or
94 # update_engine_client exited with > 0. 103 # update_engine_client exited with > 0.
95 raise ChromiumOSError('update_engine failed on %s' % 104 raise ChromiumOSError('update_engine failed on %s' %
96 self.host.hostname) 105 self.host.hostname)
97 106
98 # Check that the installer completed as expected. 107 # Check that the installer completed as expected.
99 status = self.check_update_status() 108 status = self.check_update_status()
100 if status != UPDATER_NEED_REBOOT: 109 if status != UPDATER_NEED_REBOOT:
101 # TODO(seano): should we aggressively reset update-engine here?
102 raise ChromiumOSError('update-engine error on %s: ' 110 raise ChromiumOSError('update-engine error on %s: '
103 '"%s" from update-engine' % 111 '"%s" from update-engine' %
104 (self.host.hostname, status)) 112 (self.host.hostname, status))
105 113
106 # Attempt dev & test tools update (which don't live on the 114 # Attempt dev & test tools update (which don't live on the
107 # rootfs). This must succeed so that the newly installed host 115 # rootfs). This must succeed so that the newly installed host
108 # is testable after we run the autoupdater. 116 # is testable after we run the autoupdater.
109 statefuldev_url = self.update_url.replace('update', 'static/archive') 117 statefuldev_url = self.update_url.replace('update', 'static/archive')
110 118
111 statefuldev_cmd = ' '.join([STATEFULDEV_UPDATER, statefuldev_url, 119 statefuldev_cmd = ' '.join([STATEFULDEV_UPDATER, statefuldev_url,
112 '2>&1']) 120 '2>&1'])
113 logging.info(statefuldev_cmd) 121 logging.info(statefuldev_cmd)
114 try: 122 try:
115 self._run(statefuldev_cmd, timeout=600) 123 self._run(statefuldev_cmd, timeout=600)
116 except error.AutoservRunError, e: 124 except error.AutoservRunError, e:
117 # TODO(seano): If statefuldev update failed, we must mark 125 # TODO(seano): If statefuldev update failed, we must mark
118 # the update as failed, and keep the same rootfs after 126 # the update as failed, and keep the same rootfs after
119 # reboot. 127 # reboot.
120 raise ChromiumOSError('stateful_update failed on %s' % 128 self.revert_boot_partition()
129 raise ChromiumOSError('stateful_update failed on %s.' %
121 self.host.hostname) 130 self.host.hostname)
122 return True 131 return True
123 132
124 133
125 def check_version(self): 134 def check_version(self):
126 booted_version = self.get_build_id() 135 booted_version = self.get_build_id()
127 if booted_version != self.update_version: 136 if not booted_version in self.update_version:
128 logging.error('Expected Chromium OS version: %s.' 137 logging.error('Expected Chromium OS version: %s.'
129 'Found Chromium OS %s', 138 'Found Chromium OS %s',
130 (self.update_version, booted_version)) 139 self.update_version, booted_version)
131 raise ChromiumOSError('Updater failed on host %s' % 140 raise ChromiumOSError('Updater failed on host %s' %
132 self.host.hostname) 141 self.host.hostname)
133 else: 142 else:
134 return True 143 return True
135 144
136 145
137 def get_build_id(self): 146 def get_build_id(self):
138 """Turns the CHROMEOS_RELEASE_DESCRIPTION into a string that 147 """Turns the CHROMEOS_RELEASE_DESCRIPTION into a string that
139 matches the build ID.""" 148 matches the build ID."""
140 # TODO(seano): handle dev build naming schemes. 149 # TODO(seano): handle dev build naming schemes.
141 version = self._run('grep CHROMEOS_RELEASE_DESCRIPTION' 150 version = self._run('grep CHROMEOS_RELEASE_DESCRIPTION'
142 ' /etc/lsb-release').stdout 151 ' /etc/lsb-release').stdout
143 build_re = (r'CHROMEOS_RELEASE_DESCRIPTION=' 152 build_re = (r'CHROMEOS_RELEASE_DESCRIPTION='
144 '(\d+\.\d+\.\d+\.\d+) \(\w+ \w+ (\w+)(.*)\)') 153 '(\d+\.\d+\.\d+\.\d+) \(\w+ \w+ (\w+)(.*)\)')
145 version_match = re.match(build_re, version) 154 version_match = re.match(build_re, version)
146 if not version_match: 155 if not version_match:
147 raise ChromiumOSError('Unable to get build ID from %s. Found "%s"', 156 raise ChromiumOSError('Unable to get build ID from %s. Found "%s"',
148 self.host.hostname, version) 157 self.host.hostname, version)
149 version, build_id, builder = version_match.groups() 158 version, build_id, builder = version_match.groups()
150 # Continuous builds have an extra "builder number" on the end.
151 # Report it if this looks like one.
152 build_match = re.match(r'.*: (\d+)', builder) 159 build_match = re.match(r'.*: (\d+)', builder)
153 if build_match: 160 if build_match:
154 builder_num = '-b%s' % build_match.group(1) 161 builder_num = '-b%s' % build_match.group(1)
155 else: 162 else:
156 builder_num = '' 163 builder_num = ''
157 return '%s-r%s%s' % (version, build_id, builder_num) 164 return '%s-r%s%s' % (version, build_id, builder_num)
OLDNEW
« no previous file with comments | « client/bin/site_sysinfo.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698