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

Side by Side Diff: autoupdate.py

Issue 4516004: Reduce the size of the stateful update by only copying dirs and some clean up. (Closed) Base URL: http://git.chromium.org/git/dev-util.git@master
Patch Set: Fixes for petkov Created 10 years, 1 month 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 | « no previous file | stateful_update » ('j') | 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) 2009-2010 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2009-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 from buildutil import BuildObject 5 from buildutil import BuildObject
6 from xml.dom import minidom 6 from xml.dom import minidom
7
8 import cherrypy 7 import cherrypy
9 import os 8 import os
10 import shutil 9 import shutil
11 import socket 10 import subprocess
11 import tempfile
12 import time 12 import time
13 13
14
14 def _LogMessage(message): 15 def _LogMessage(message):
15 cherrypy.log(message, 'UPDATE') 16 cherrypy.log(message, 'UPDATE')
16 17
17 18
18 class Autoupdate(BuildObject): 19 class Autoupdate(BuildObject):
19 """Class that contains functionality that handles Chrome OS update pings. 20 """Class that contains functionality that handles Chrome OS update pings.
20 21
21 Members: 22 Members:
22 serve_only: Serve images from a pre-built image.zip file. static_dir 23 serve_only: Serve images from a pre-built image.zip file. static_dir
23 must be set to the location of the image.zip. 24 must be set to the location of the image.zip.
(...skipping 17 matching lines...) Expand all
41 self.urlbase = urlbase 42 self.urlbase = urlbase
42 else: 43 else:
43 self.urlbase = None 44 self.urlbase = None
44 45
45 self.client_prefix = client_prefix 46 self.client_prefix = client_prefix
46 self.forced_image = forced_image 47 self.forced_image = forced_image
47 self.use_cached = use_cached 48 self.use_cached = use_cached
48 self.src_image = src_image 49 self.src_image = src_image
49 self.vm = vm 50 self.vm = vm
50 self.board = board 51 self.board = board
52 self.crosutils = os.path.join(os.path.dirname(__file__), '../../scripts')
51 53
52 def _GetSecondsSinceMidnight(self): 54 def _GetSecondsSinceMidnight(self):
53 """Returns the seconds since midnight as a decimal value.""" 55 """Returns the seconds since midnight as a decimal value."""
54 now = time.localtime() 56 now = time.localtime()
55 return now[3] * 3600 + now[4] * 60 + now[5] 57 return now[3] * 3600 + now[4] * 60 + now[5]
56 58
57 def _GetDefaultBoardID(self): 59 def _GetDefaultBoardID(self):
58 """Returns the default board id stored in .default_board.""" 60 """Returns the default board id stored in .default_board."""
59 board_file = '%s/.default_board' % (self.scripts_dir) 61 board_file = '%s/.default_board' % (self.scripts_dir)
60 try: 62 try:
(...skipping 16 matching lines...) Expand all
77 client_tokens = client_version.replace('_', '').split('.') 79 client_tokens = client_version.replace('_', '').split('.')
78 latest_tokens = latest_version.replace('_', '').split('.') 80 latest_tokens = latest_version.replace('_', '').split('.')
79 _LogMessage('client version %s latest version %s' 81 _LogMessage('client version %s latest version %s'
80 % (client_version, latest_version)) 82 % (client_version, latest_version))
81 for i in range(4): 83 for i in range(4):
82 if int(latest_tokens[i]) == int(client_tokens[i]): 84 if int(latest_tokens[i]) == int(client_tokens[i]):
83 continue 85 continue
84 return int(latest_tokens[i]) > int(client_tokens[i]) 86 return int(latest_tokens[i]) > int(client_tokens[i])
85 return False 87 return False
86 88
87 def _UnpackStatefulPartition(self, image_path, stateful_file):
88 """Given an image, unpacks its stateful partition to stateful_file."""
89 image_dir = os.path.dirname(image_path)
90 image_file = os.path.basename(image_path)
91
92 get_offset = '$(cgpt show -b -i 1 %s)' % image_file
93 get_size = '$(cgpt show -s -i 1 %s)' % image_file
94 unpack_command = (
95 'cd %s && '
96 'dd if=%s of=%s bs=512 skip=%s count=%s' % (image_dir, image_file,
97 stateful_file, get_offset,
98 get_size))
99 _LogMessage(unpack_command)
100 return os.system(unpack_command) == 0
101
102 def _UnpackZip(self, image_dir): 89 def _UnpackZip(self, image_dir):
103 """Unpacks an image.zip into a given directory.""" 90 """Unpacks an image.zip into a given directory."""
104 image = os.path.join(image_dir, self._GetImageName()) 91 image = os.path.join(image_dir, self._GetImageName())
105 if os.path.exists(image): 92 if os.path.exists(image):
106 return True 93 return True
107 else: 94 else:
108 # -n, never clobber an existing file, in case we get invoked 95 # -n, never clobber an existing file, in case we get invoked
109 # simultaneously by multiple request handlers. This means that 96 # simultaneously by multiple request handlers. This means that
110 # we're assuming each image.zip file lives in a versioned 97 # we're assuming each image.zip file lives in a versioned
111 # directory (a la Buildbot). 98 # directory (a la Buildbot).
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 return update_path 228 return update_path
242 229
243 def GenerateStatefulFile(self, image_path): 230 def GenerateStatefulFile(self, image_path):
244 """Generates a stateful update gz given a full path to an image. 231 """Generates a stateful update gz given a full path to an image.
245 232
246 Args: 233 Args:
247 image_path: Full path to image. 234 image_path: Full path to image.
248 Returns: 235 Returns:
249 Path to created stateful update_payload or None on error. 236 Path to created stateful update_payload or None on error.
250 """ 237 """
251 stateful_partition_path = '%s/stateful.image' % os.path.dirname(image_path) 238 _LogMessage('Generating stateful update file.')
239 from_dir = os.path.dirname(image_path)
240 image = os.path.basename(image_path)
241 output_gz = os.path.join(from_dir, 'stateful.tgz')
252 242
253 # Unpack to get stateful partition. 243 # Temporary directories for this function.
254 if self._UnpackStatefulPartition(image_path, stateful_partition_path): 244 rootfs_dir = tempfile.mkdtemp(suffix='rootfs', prefix='tmp')
255 mkstatefulupdate_command = 'gzip -f %s' % stateful_partition_path 245 stateful_dir = tempfile.mkdtemp(suffix='stateful', prefix='tmp')
256 if os.system(mkstatefulupdate_command) == 0:
257 _LogMessage('Successfully generated %s.gz' % stateful_partition_path)
258 return '%s.gz' % stateful_partition_path
259 246
260 _LogMessage('Failed to create stateful update file') 247 # Mount the image to pull out the important directories.
261 return None 248 try:
249 # Only need stateful partition, but this saves us having to manage our
250 # own loopback device.
251 subprocess.check_call(['%s/mount_gpt_image.sh' % self.crosutils,
252 '--from=%s' % from_dir,
253 '--image=%s' % image,
254 '--read_only',
255 '--rootfs_mountpt=%s' % rootfs_dir,
256 '--stateful_mountpt=%s' % stateful_dir,
257 ])
258 _LogMessage('Tarring up /usr/local and /var!')
259 subprocess.check_call(['sudo',
260 'tar',
261 '-czf',
262 output_gz,
263 '--directory=%s' % stateful_dir,
264 'dev_image',
265 'var',
266 ])
267 except:
268 _LogMessage('Failed to create stateful update file')
269 raise
270 finally:
271 # Unmount best effort regardless.
272 subprocess.call(['%s/mount_gpt_image.sh' % self.crosutils,
273 '--unmount',
274 '--rootfs_mountpt=%s' % rootfs_dir,
275 '--stateful_mountpt=%s' % stateful_dir,
276 ])
277 # Clean up our directories.
278 os.rmdir(rootfs_dir)
279 os.rmdir(stateful_dir)
280
281 _LogMessage('Successfully generated %s' % output_gz)
282 return output_gz
262 283
263 def MoveImagesToStaticDir(self, update_path, stateful_update_path, 284 def MoveImagesToStaticDir(self, update_path, stateful_update_path,
264 static_image_dir): 285 static_image_dir):
265 """Moves gz files from their directories to serving directories. 286 """Moves gz files from their directories to serving directories.
266 287
267 Args: 288 Args:
268 update_path: full path to main update gz. 289 update_path: full path to main update gz.
269 stateful_update_path: full path to stateful partition gz. 290 stateful_update_path: full path to stateful partition gz.
270 static_image_dir: where to put files. 291 static_image_dir: where to put files.
271 Returns: 292 Returns:
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 is_delta_format = self._IsDeltaFormatFile(filename) 588 is_delta_format = self._IsDeltaFormatFile(filename)
568 if label: 589 if label:
569 url = '%s/%s/update.gz' % (static_urlbase, label) 590 url = '%s/%s/update.gz' % (static_urlbase, label)
570 else: 591 else:
571 url = '%s/update.gz' % static_urlbase 592 url = '%s/update.gz' % static_urlbase
572 593
573 _LogMessage('Responding to client to use url %s to get image.' % url) 594 _LogMessage('Responding to client to use url %s to get image.' % url)
574 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format) 595 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format)
575 else: 596 else:
576 return self.GetNoUpdatePayload() 597 return self.GetNoUpdatePayload()
OLDNEW
« no previous file with comments | « no previous file | stateful_update » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698