Commit ecfd53c1 authored by Wez's avatar Wez Committed by Commit Bot

[fuchsia] Fix RunPackage() to keep 'pm serve' live while running.

Fuchsia packages are cached rather than installed into a device's
package filesystem, and when resolving packages the system is at liberty
to return a cached package that may be older than the version that had
previously been run, if the package server is unavailable.

Ensure that the package server remains running for the duration of
RunPackage(), to ensure that the expected version is run.

Bug: 956100, fuchsia:49180
Change-Id: I4aeacbf451f5c2bde84e16b3ea35461d2b88fa4b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2127368
Commit-Queue: Wez <wez@chromium.org>
Auto-Submit: Wez <wez@chromium.org>
Reviewed-by: default avatarKevin Marshall <kmarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754690}
parent f3f8d5dd
...@@ -41,6 +41,7 @@ class ManagedAmberRepo(AmberRepo): ...@@ -41,6 +41,7 @@ class ManagedAmberRepo(AmberRepo):
def __init__(self, target): def __init__(self, target):
AmberRepo.__init__(self, target) AmberRepo.__init__(self, target)
self._with_count = 0
self._amber_root = tempfile.mkdtemp() self._amber_root = tempfile.mkdtemp()
pm_tool = common.GetHostToolPathFromPlatform('pm') pm_tool = common.GetHostToolPathFromPlatform('pm')
...@@ -71,18 +72,23 @@ class ManagedAmberRepo(AmberRepo): ...@@ -71,18 +72,23 @@ class ManagedAmberRepo(AmberRepo):
self._RegisterAmberRepository(self._amber_root, remote_port) self._RegisterAmberRepository(self._amber_root, remote_port)
def __enter__(self): def __enter__(self):
self._with_count += 1
return self return self
def __exit__(self, type, value, tb): def __exit__(self, type, value, tb):
"""Allows the repository to delete itself when it leaves the scope of a """Allows the repository to delete itself when it leaves the scope of a
'with' block.""" 'with' block."""
if self._amber_root: self._with_count -= 1
if self._with_count > 0:
return
logging.info('Cleaning up Amber root: ' + self._amber_root) logging.info('Cleaning up Amber root: ' + self._amber_root)
shutil.rmtree(self._amber_root) shutil.rmtree(self._amber_root)
self._amber_root = None
self._UnregisterAmberRepository() self._UnregisterAmberRepository()
if self._pm_serve_task:
self._pm_serve_task.kill() self._pm_serve_task.kill()
self._pm_serve_task = None
def GetPath(self): def GetPath(self):
return self._amber_root return self._amber_root
...@@ -94,7 +100,7 @@ class ManagedAmberRepo(AmberRepo): ...@@ -94,7 +100,7 @@ class ManagedAmberRepo(AmberRepo):
|remote_port|: The reverse-forwarded port used to connect to instance of |remote_port|: The reverse-forwarded port used to connect to instance of
`pm serve` that is serving the contents of |tuf_repo|.""" `pm serve` that is serving the contents of |tuf_repo|."""
# Extract the public signing key for inclusion in the config file. # Extract the public signing key for inclusion in the config file.
root_keys = [] root_keys = []
root_json_path = os.path.join(tuf_repo, 'repository', 'root.json') root_json_path = os.path.join(tuf_repo, 'repository', 'root.json')
root_json = json.load(open(root_json_path, 'r')) root_json = json.load(open(root_json_path, 'r'))
...@@ -153,7 +159,8 @@ class ExternalAmberRepo(AmberRepo): ...@@ -153,7 +159,8 @@ class ExternalAmberRepo(AmberRepo):
self._amber_root = amber_root self._amber_root = amber_root
logging.info('Using existing Amber root: {}'.format(amber_root)) logging.info('Using existing Amber root: {}'.format(amber_root))
#TODO(kmarshall) : Find a way to programatically check if "fx serve" is running. # TODO(kmarshall): Find a way to programmatically check if "fx serve" is
# running.
logging.info('Ensure that "fx serve" is running.') logging.info('Ensure that "fx serve" is running.')
def GetPath(self): def GetPath(self):
......
...@@ -217,7 +217,7 @@ class DeviceTarget(target.Target): ...@@ -217,7 +217,7 @@ class DeviceTarget(target.Target):
assert self._host assert self._host
def _GetAmberRepo(self): def GetAmberRepo(self):
if not self._amber_repo: if not self._amber_repo:
if self._fuchsia_out_dir: if self._fuchsia_out_dir:
# Deploy to an already-booted device running a local Fuchsia build. # Deploy to an already-booted device running a local Fuchsia build.
......
...@@ -75,7 +75,7 @@ class EmuTarget(target.Target): ...@@ -75,7 +75,7 @@ class EmuTarget(target.Target):
open(temporary_system_log_file.name, 'r').read()) open(temporary_system_log_file.name, 'r').read())
raise raise
def _GetAmberRepo(self): def GetAmberRepo(self):
if not self._amber_repo: if not self._amber_repo:
self._amber_repo = amber_repo.ManagedAmberRepo(self) self._amber_repo = amber_repo.ManagedAmberRepo(self)
......
...@@ -161,13 +161,15 @@ def RunPackage(output_dir, target, package_paths, package_name, ...@@ -161,13 +161,15 @@ def RunPackage(output_dir, target, package_paths, package_name,
system_logger = ( system_logger = (
_AttachKernelLogReader(target) if args.system_logging else None) _AttachKernelLogReader(target) if args.system_logging else None)
try: try:
with target.GetAmberRepo():
if system_logger: if system_logger:
# Spin up a thread to asynchronously dump the system log to stdout # Spin up a thread to asynchronously dump the system log to stdout
# for easier diagnoses of early, pre-execution failures. # for easier diagnoses of early, pre-execution failures.
log_output_quit_event = multiprocessing.Event() log_output_quit_event = multiprocessing.Event()
log_output_thread = threading.Thread( log_output_thread = threading.Thread(
target=lambda: _DrainStreamToStdout(system_logger.stdout, target=
log_output_quit_event)) lambda: _DrainStreamToStdout(system_logger.stdout, log_output_quit_event)
)
log_output_thread.daemon = True log_output_thread.daemon = True
log_output_thread.start() log_output_thread.start()
...@@ -179,14 +181,15 @@ def RunPackage(output_dir, target, package_paths, package_name, ...@@ -179,14 +181,15 @@ def RunPackage(output_dir, target, package_paths, package_name,
logging.info('Running application.') logging.info('Running application.')
command = ['run', _GetComponentUri(package_name)] + package_args command = ['run', _GetComponentUri(package_name)] + package_args
process = target.RunCommandPiped(command, process = target.RunCommandPiped(
command,
stdin=open(os.devnull, 'r'), stdin=open(os.devnull, 'r'),
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
if system_logger: if system_logger:
output_stream = MergedInputStream([process.stdout, output_stream = MergedInputStream(
system_logger.stdout]).Start() [process.stdout, system_logger.stdout]).Start()
else: else:
output_stream = process.stdout output_stream = process.stdout
...@@ -206,8 +209,8 @@ def RunPackage(output_dir, target, package_paths, package_name, ...@@ -206,8 +209,8 @@ def RunPackage(output_dir, target, package_paths, package_name,
else: else:
# The test runner returns an error status code if *any* tests fail, # The test runner returns an error status code if *any* tests fail,
# so we should proceed anyway. # so we should proceed anyway.
logging.warning('Process exited with status code %d.' % logging.warning(
process.returncode) 'Process exited with status code %d.' % process.returncode)
finally: finally:
if system_logger: if system_logger:
......
...@@ -236,8 +236,12 @@ class Target(object): ...@@ -236,8 +236,12 @@ class Target(object):
return 'x86_64' return 'x86_64'
raise Exception('Unknown target_cpu %s:' % self._target_cpu) raise Exception('Unknown target_cpu %s:' % self._target_cpu)
def _GetAmberRepo(self): def GetAmberRepo(self):
"""Returns an AmberRepo instance which serves packages for this Target.""" """Returns an AmberRepo instance which serves packages for this Target.
Callers should typically call GetAmberRepo() in a |with| statement, and
install and execute commands inside the |with| block, so that the returned
AmberRepo can teardown correctly, if necessary.
"""
pass pass
def InstallPackage(self, package_paths): def InstallPackage(self, package_paths):
...@@ -246,7 +250,7 @@ class Target(object): ...@@ -246,7 +250,7 @@ class Target(object):
package_paths: Paths to the .far files to install.""" package_paths: Paths to the .far files to install."""
with self._GetAmberRepo() as amber_repo: with self.GetAmberRepo() as amber_repo:
# Publish all packages to the serving TUF repository under |tuf_root|. # Publish all packages to the serving TUF repository under |tuf_root|.
for next_package_path in package_paths: for next_package_path in package_paths:
amber_repo.PublishPackage(next_package_path) amber_repo.PublishPackage(next_package_path)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment