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

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

Issue 3175034: call update_engine_client and wait on exit code. (Closed) Base URL: http://src.chromium.org/git/autotest.git
Patch Set: Created 10 years, 4 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
« no previous file with comments | « no previous file | 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 site_utils
12 from autotest_lib.client.common_lib import error 11 from autotest_lib.client.common_lib import error
13 12
14
15 STATEFULDEV_UPDATER = '/usr/local/bin/stateful_update' 13 STATEFULDEV_UPDATER = '/usr/local/bin/stateful_update'
16 UPDATER_BIN = '/usr/bin/update_engine_client' 14 UPDATER_BIN = '/usr/bin/update_engine_client'
17 UPDATER_IDLE = 'UPDATE_STATUS_IDLE' 15 UPDATER_IDLE = 'UPDATE_STATUS_IDLE'
18 UPDATER_NEED_REBOOT = 'UPDATED_NEED_REBOOT' 16 UPDATER_NEED_REBOOT = 'UPDATE_STATUS_UPDATED_NEED_REBOOT'
19 17
20 18
21 class ChromiumOSError(error.InstallError): 19 class ChromiumOSError(error.InstallError):
22 """Generic error for ChromiumOS-specific exceptions.""" 20 """Generic error for ChromiumOS-specific exceptions."""
23 pass 21 pass
24 22
25 23
26 def url_to_version(update_url): 24 def url_to_version(update_url):
27 # The ChromiumOS updater respects the last element in the path as 25 # The ChromiumOS updater respects the last element in the path as
28 # the requested version. Parse it out. 26 # the requested version. Parse it out.
29 return urlparse.urlparse(update_url).path.split('/')[-1] 27 return urlparse.urlparse(update_url).path.split('/')[-1]
30 28
31 29
32 class ChromiumOSUpdater(): 30 class ChromiumOSUpdater():
33 def __init__(self, host=None, update_url=None): 31 def __init__(self, host=None, update_url=None):
34 self.host = host 32 self.host = host
35 self.update_url = update_url 33 self.update_url = update_url
36 self.update_version = url_to_version(update_url) 34 self.update_version = url_to_version(update_url)
37 35
36
38 def check_update_status(self): 37 def check_update_status(self):
39 update_status_cmd = ' '.join([UPDATER_BIN, '-status', '2>&1', 38 update_status_cmd = ' '.join([UPDATER_BIN, '-status', '2>&1',
40 '| grep CURRENT_OP']) 39 '| grep CURRENT_OP'])
41 update_status = self._run(update_status_cmd) 40 update_status = self._run(update_status_cmd)
42 return update_status.stdout.strip().split('=')[-1] 41 return update_status.stdout.strip().split('=')[-1]
43 42
43
44 def reset_update_engine(self):
45 self._run('initctl stop update-engine')
petkov 2010/08/23 19:20:31 Does this throw an exception if update-engine is n
46 self._run('rm -f /tmp/update_engine_autoupdate_completed')
47 self._run('initctl start update-engine')
48 # May need to wait if service becomes slow to restart.
49 if self.check_update_status() != UPDATER_IDLE:
50 raise ChromiumOSError('%s is not in an installable state' %
51 self.host.hostname)
52
53
44 def _run(self, cmd, *args, **kwargs): 54 def _run(self, cmd, *args, **kwargs):
45 return self.host.run(cmd, *args, **kwargs) 55 return self.host.run(cmd, *args, **kwargs)
46 56
57
47 def run_update(self): 58 def run_update(self):
48 # TODO(seano): Retrieve update_engine.log from target host. 59 # TODO(seano): Retrieve update_engine.log from target host.
49 if not self.update_url: 60 if not self.update_url:
50 return False 61 return False
51 62
52 # Check that devserver is accepting connections (from autoserv's host) 63 # Check that devserver is accepting connections (from autoserv's host)
53 # If we can't talk to it, the machine host probably can't either. 64 # If we can't talk to it, the machine host probably can't either.
54 auserver_host = urlparse.urlparse(self.update_url)[1] 65 auserver_host = urlparse.urlparse(self.update_url)[1]
55 try: 66 try:
56 httplib.HTTPConnection(auserver_host).connect() 67 httplib.HTTPConnection(auserver_host).connect()
57 except socket.error: 68 except socket.error:
58 raise ChromiumOSError('Update server at %s not available' % 69 raise ChromiumOSError('Update server at %s not available' %
59 auserver_host) 70 auserver_host)
60 71
61 logging.info('Installing from %s to: %s' % (self.update_url, 72 logging.info('Installing from %s to: %s' % (self.update_url,
62 self.host.hostname)) 73 self.host.hostname))
63 # If we find the system an updated-but-not-rebooted state, 74 # If we find the system an updated-but-not-rebooted state,
64 # that's probably bad and we shouldn't trust that the previous 75 # that's probably bad and we shouldn't trust that the previous
65 # update left the machine in a good state. Reset update_engine's 76 # update left the machine in a good state. Reset update_engine's
66 # state & ensure that update_engine is idle. 77 # state & ensure that update_engine is idle.
67 if self.check_update_status() != UPDATER_IDLE: 78 if self.check_update_status() != UPDATER_IDLE:
petkov 2010/08/23 19:20:31 This may throw an exception if update-engine is no
68 self._run('initctl stop update-engine') 79 self.reset_update_engine()
69 self._run('rm -f /tmp/update_engine_autoupdate_completed') 80
70 self._run('initctl start update-engine') 81 # Run autoupdate command. This tells the autoupdate process on
71 # May need to wait if service becomes slow to restart. 82 # the host to look for an update at a specific URL and version
72 if self.check_update_status() != UPDATER_IDLE: 83 # string.
73 raise ChromiumOSError('%s is not in an installable state' % 84 autoupdate_cmd = ' '.join([UPDATER_BIN,
85 '--update',
86 '--omaha_url=%s' % self.update_url,
87 '--app_version ForcedUpdate',
petkov 2010/08/23 19:20:31 FYI, currently --update implies --app_version=Forc
88 ' 2>&1'])
89 logging.info(autoupdate_cmd)
90 try:
91 self._run(autoupdate_cmd, timeout=900)
92 except error.AutoservRunError, e:
93 # Either a runtime error occurred on the host, or
94 # update_engine_client exited with > 0.
95 raise ChromiumOSError('update_engine failed on %s' %
74 self.host.hostname) 96 self.host.hostname)
75 97
76 # First, attempt dev & test tools update (which don't live on 98 # Check that the installer completed as expected.
77 # the rootfs). This must succeed so that the newly installed 99 status = self.check_update_status()
78 # host is testable after we run the autoupdater. 100 if status != UPDATER_NEED_REBOOT:
101 # TODO(seano): should we aggressively reset update-engine here?
petkov 2010/08/23 19:20:31 It might be good to somehow log /var/log/update_en
102 raise ChromiumOSError('update-engine error on %s: '
103 '"%s" from update-engine' %
104 (self.host.hostname, status))
105
106 # Attempt dev & test tools update (which don't live on the
107 # rootfs). This must succeed so that the newly installed host
108 # is testable after we run the autoupdater.
79 statefuldev_url = self.update_url.replace('update', 'static/archive') 109 statefuldev_url = self.update_url.replace('update', 'static/archive')
80 110
81 statefuldev_cmd = ' '.join([STATEFULDEV_UPDATER, statefuldev_url, 111 statefuldev_cmd = ' '.join([STATEFULDEV_UPDATER, statefuldev_url,
82 '2>&1']) 112 '2>&1'])
83 logging.info(statefuldev_cmd) 113 logging.info(statefuldev_cmd)
84 try: 114 try:
85 self._run(statefuldev_cmd, timeout=1200) 115 self._run(statefuldev_cmd, timeout=600)
86 except error.AutoservRunError, e: 116 except error.AutoservRunError, e:
117 # TODO(seano): If statefuldev update failed, we must mark
118 # the update as failed, and keep the same rootfs after
119 # reboot.
87 raise ChromiumOSError('stateful_update failed on %s' % 120 raise ChromiumOSError('stateful_update failed on %s' %
88 self.host.hostname) 121 self.host.hostname)
89
90 # Run autoupdate command. This tells the autoupdate process on
91 # the host to look for an update at a specific URL and version
92 # string.
93 autoupdate_cmd = ' '.join([UPDATER_BIN,
94 '--omaha_url=%s' % self.update_url,
95 '--app_version ForcedUpdate'])
96 logging.info(autoupdate_cmd)
97 try:
98 self._run(autoupdate_cmd, timeout=60)
99 except error.AutoservRunError, e:
100 raise ChromiumOSError('unable to run updater on %s' %
101 self.host.hostname)
102
103 # Check that the installer completed as expected.
104 def update_successful():
105 status = self.check_update_status()
106 if status == UPDATER_IDLE:
107 raise ChromiumOSError('update-engine error on %s' %
108 self.host.hostname)
109 else:
110 return 'UPDATED_NEED_REBOOT' in status
111
112 site_utils.poll_for_condition(update_successful,
113 ChromiumOSError('Updater failed'),
114 900, 10)
115 return True 122 return True
116 123
117 124
118 def check_version(self): 125 def check_version(self):
119 booted_version = self.get_build_id() 126 booted_version = self.get_build_id()
120 if booted_version != self.update_version: 127 if booted_version != self.update_version:
121 logging.error('Expected Chromium OS version: %s.' 128 logging.error('Expected Chromium OS version: %s.'
122 'Found Chromium OS %s', 129 'Found Chromium OS %s',
123 (self.update_version, booted_version)) 130 (self.update_version, booted_version))
124 raise ChromiumOSError('Updater failed on host %s' % 131 raise ChromiumOSError('Updater failed on host %s' %
125 self.host.hostname) 132 self.host.hostname)
126 else: 133 else:
127 return True 134 return True
128 135
136
129 def get_build_id(self): 137 def get_build_id(self):
130 """Turns the CHROMEOS_RELEASE_DESCRIPTION into a string that 138 """Turns the CHROMEOS_RELEASE_DESCRIPTION into a string that
131 matches the build ID.""" 139 matches the build ID."""
132 # TODO(seano): handle dev build naming schemes. 140 # TODO(seano): handle dev build naming schemes.
133 version = self._run('grep CHROMEOS_RELEASE_DESCRIPTION' 141 version = self._run('grep CHROMEOS_RELEASE_DESCRIPTION'
134 ' /etc/lsb-release').stdout 142 ' /etc/lsb-release').stdout
135 build_re = (r'CHROMEOS_RELEASE_DESCRIPTION=' 143 build_re = (r'CHROMEOS_RELEASE_DESCRIPTION='
136 '(\d+\.\d+\.\d+\.\d+) \(\w+ \w+ (\w+)(.*)\)') 144 '(\d+\.\d+\.\d+\.\d+) \(\w+ \w+ (\w+)(.*)\)')
137 version_match = re.match(build_re, version) 145 version_match = re.match(build_re, version)
138 if not version_match: 146 if not version_match:
139 raise ChromiumOSError('Unable to get build ID from %s. Found "%s"', 147 raise ChromiumOSError('Unable to get build ID from %s. Found "%s"',
140 self.host.hostname, version) 148 self.host.hostname, version)
141 version, build_id, builder = version_match.groups() 149 version, build_id, builder = version_match.groups()
142 # Continuous builds have an extra "builder number" on the end. 150 # Continuous builds have an extra "builder number" on the end.
143 # Report it if this looks like one. 151 # Report it if this looks like one.
144 build_match = re.match(r'.*: (\d+)', builder) 152 build_match = re.match(r'.*: (\d+)', builder)
145 if build_match: 153 if build_match:
146 builder_num = '-b%s' % build_match.group(1) 154 builder_num = '-b%s' % build_match.group(1)
147 else: 155 else:
148 builder_num = '' 156 builder_num = ''
149 return '%s-r%s%s' % (version, build_id, builder_num) 157 return '%s-r%s%s' % (version, build_id, builder_num)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698