Ejemplo n.º 1
0
def delete_and_upload(storage, out_dir, leak_temp_dir):
    """Deletes the temporary run directory and uploads results back.

  Returns:
    tuple(outputs_ref, success, stats)
    - outputs_ref: a dict referring to the results archived back to the isolated
          server, if applicable.
    - success: False if something occurred that means that the task must
          forcibly be considered a failure, e.g. zombie processes were left
          behind.
    - stats: uploading stats.
  """

    # Upload out_dir and generate a .isolated file out of this directory. It is
    # only done if files were written in the directory.
    outputs_ref = None
    cold = []
    hot = []
    start = time.time()

    if fs.isdir(out_dir) and fs.listdir(out_dir):
        with tools.Profiler('ArchiveOutput'):
            try:
                results, f_cold, f_hot = isolateserver.archive_files_to_storage(
                    storage, [out_dir], None)
                outputs_ref = {
                    'isolated': results[0][0],
                    'isolatedserver': storage.location,
                    'namespace': storage.namespace,
                }
                cold = sorted(i.size for i in f_cold)
                hot = sorted(i.size for i in f_hot)
            except isolateserver.Aborted:
                # This happens when a signal SIGTERM was received while uploading data.
                # There is 2 causes:
                # - The task was too slow and was about to be killed anyway due to
                #   exceeding the hard timeout.
                # - The amount of data uploaded back is very large and took too much
                #   time to archive.
                sys.stderr.write('Received SIGTERM while uploading')
                # Re-raise, so it will be treated as an internal failure.
                raise

    success = False
    try:
        if (not leak_temp_dir and fs.isdir(out_dir)
                and not file_path.rmtree(out_dir)):
            logging.error('Had difficulties removing out_dir %s', out_dir)
        else:
            success = True
    except OSError as e:
        # When this happens, it means there's a process error.
        logging.exception('Had difficulties removing out_dir %s: %s', out_dir,
                          e)
    stats = {
        'duration': time.time() - start,
        'items_cold': base64.b64encode(large.pack(cold)),
        'items_hot': base64.b64encode(large.pack(hot)),
    }
    return outputs_ref, success, stats
Ejemplo n.º 2
0
def fetch_and_map(isolated_hash, storage, cache, outdir, use_symlinks):
  """Fetches an isolated tree, create the tree and returns (bundle, stats)."""
  start = time.time()
  bundle = isolateserver.fetch_isolated(
      isolated_hash=isolated_hash,
      storage=storage,
      cache=cache,
      outdir=outdir,
      use_symlinks=use_symlinks)
  return bundle, {
    'duration': time.time() - start,
    'items_cold': base64.b64encode(large.pack(sorted(cache.added))),
    'items_hot': base64.b64encode(
        large.pack(sorted(set(cache.used) - set(cache.added)))),
  }
Ejemplo n.º 3
0
 def test_1m_pseudo(self):
     # Compresses a pseudo-random suite. Still compresses very well.
     random.seed(0)
     array = sorted(random.randint(0, 1000000) for _ in xrange(1000000))
     data = large.pack(array)
     self.assertGreater(302000, len(data))
     self.assertEqual(array, large.unpack(data))
Ejemplo n.º 4
0
 def test_1m_pseudo(self):
   # Compresses a pseudo-random suite. Still compresses very well.
   random.seed(0)
   array = sorted(random.randint(0, 1000000) for _ in xrange(1000000))
   data = large.pack(array)
   self.assertGreater(302000, len(data))
   self.assertEqual(array, large.unpack(data))
Ejemplo n.º 5
0
 def test_empty(self):
     self.assertEqual('', large.pack([]))
     self.assertEqual([], large.unpack(''))
Ejemplo n.º 6
0
 def test_1m_1000(self):
     array = [i * 1000 for i in xrange(1000000)]
     data = large.pack(array)
     self.assertGreater(2000, len(data))
     self.assertEqual(array, large.unpack(data))
Ejemplo n.º 7
0
 def test_1m_1(self):
     array = range(1000000)
     data = large.pack(array)
     self.assertGreater(1000, len(data))
     self.assertEqual(array, large.unpack(data))
Ejemplo n.º 8
0
 def test_empty(self):
   self.assertEqual('', large.pack([]))
   self.assertEqual([], large.unpack(''))
Ejemplo n.º 9
0
 def test_1m_1000(self):
   array = [i*1000 for i in xrange(1000000)]
   data = large.pack(array)
   self.assertGreater(2000, len(data))
   self.assertEqual(array, large.unpack(data))
Ejemplo n.º 10
0
 def test_1m_1(self):
   array = range(1000000)
   data = large.pack(array)
   self.assertGreater(1000, len(data))
   self.assertEqual(array, large.unpack(data))
Ejemplo n.º 11
0
def map_and_run(
    isolated_hash, storage, cache, leak_temp_dir, root_dir, hard_timeout,
    grace_period, extra_args):
  """Maps and run the command. Returns metadata about the result."""
  result = {
    'duration': None,
    'exit_code': None,
    'had_hard_timeout': False,
    'internal_failure': None,
    'stats': {
    #  'download': {
    #    'duration': 0.,
    #    'initial_number_items': 0,
    #    'initial_size': 0,
    #    'items_cold': '<large.pack()>',
    #    'items_hot': '<large.pack()>',
    #  },
    #  'upload': {
    #    'duration': 0.,
    #    'items_cold': '<large.pack()>',
    #    'items_hot': '<large.pack()>',
    #  },
    },
    'outputs_ref': None,
    'version': 3,
  }
  if root_dir:
    if not fs.isdir(root_dir):
      fs.makedirs(root_dir, 0700)
    prefix = u''
  else:
    root_dir = os.path.dirname(cache.cache_dir) if cache.cache_dir else None
    prefix = u'isolated_'
  run_dir = make_temp_dir(prefix + u'run', root_dir)
  out_dir = make_temp_dir(prefix + u'out', root_dir)
  tmp_dir = make_temp_dir(prefix + u'tmp', root_dir)
  try:
    start = time.time()
    bundle = isolateserver.fetch_isolated(
        isolated_hash=isolated_hash,
        storage=storage,
        cache=cache,
        outdir=run_dir)
    if not bundle.command:
      # Handle this as a task failure, not an internal failure.
      sys.stderr.write(
          '<The .isolated doesn\'t declare any command to run!>\n'
          '<Check your .isolate for missing \'command\' variable>\n')
      if os.environ.get('SWARMING_TASK_ID'):
        # Give an additional hint when running as a swarming task.
        sys.stderr.write('<This occurs at the \'isolate\' step>\n')
      result['exit_code'] = 1
      return result
    result['stats']['download'] = {
      'duration': time.time() - start,
      'initial_number_items': cache.initial_number_items,
      'initial_size': cache.initial_size,
      'items_cold': base64.b64encode(large.pack(sorted(cache.added))),
      'items_hot': base64.b64encode(
          large.pack(sorted(set(cache.linked) - set(cache.added)))),
    }

    change_tree_read_only(run_dir, bundle.read_only)
    cwd = os.path.normpath(os.path.join(run_dir, bundle.relative_cwd))
    command = bundle.command + extra_args
    file_path.ensure_command_has_abs_path(command, cwd)
    sys.stdout.flush()
    start = time.time()
    try:
      result['exit_code'], result['had_hard_timeout'] = run_command(
          process_command(command, out_dir), cwd, tmp_dir, hard_timeout,
          grace_period)
    finally:
      result['duration'] = max(time.time() - start, 0)
  except Exception as e:
    # An internal error occured. Report accordingly so the swarming task will be
    # retried automatically.
    logging.exception('internal failure: %s', e)
    result['internal_failure'] = str(e)
    on_error.report(None)
  finally:
    try:
      if leak_temp_dir:
        logging.warning(
            'Deliberately leaking %s for later examination', run_dir)
      else:
        # On Windows rmtree(run_dir) call above has a synchronization effect: it
        # finishes only when all task child processes terminate (since a running
        # process locks *.exe file). Examine out_dir only after that call
        # completes (since child processes may write to out_dir too and we need
        # to wait for them to finish).
        if fs.isdir(run_dir):
          try:
            success = file_path.rmtree(run_dir)
          except OSError as e:
            logging.error('Failure with %s', e)
            success = False
          if not success:
            print >> sys.stderr, (
                'Failed to delete the run directory, forcibly failing\n'
                'the task because of it. No zombie process can outlive a\n'
                'successful task run and still be marked as successful.\n'
                'Fix your stuff.')
            if result['exit_code'] == 0:
              result['exit_code'] = 1
        if fs.isdir(tmp_dir):
          try:
            success = file_path.rmtree(tmp_dir)
          except OSError as e:
            logging.error('Failure with %s', e)
            success = False
          if not success:
            print >> sys.stderr, (
                'Failed to delete the temporary directory, forcibly failing\n'
                'the task because of it. No zombie process can outlive a\n'
                'successful task run and still be marked as successful.\n'
                'Fix your stuff.')
            if result['exit_code'] == 0:
              result['exit_code'] = 1

      # This deletes out_dir if leak_temp_dir is not set.
      start = time.time()
      result['outputs_ref'], success, cold, hot = delete_and_upload(
          storage, out_dir, leak_temp_dir)
      result['stats']['upload'] = {
        'duration': time.time() - start,
        'items_cold': base64.b64encode(large.pack(cold)),
        'items_hot': base64.b64encode(large.pack(hot)),
      }
      if not success and result['exit_code'] == 0:
        result['exit_code'] = 1
    except Exception as e:
      # Swallow any exception in the main finally clause.
      logging.exception('Leaking out_dir %s: %s', out_dir, e)
      result['internal_failure'] = str(e)
  return result
Ejemplo n.º 12
0
def map_and_run(isolated_hash, storage, cache, leak_temp_dir, root_dir,
                hard_timeout, grace_period, extra_args):
    """Maps and run the command. Returns metadata about the result."""
    result = {
        'duration': None,
        'exit_code': None,
        'had_hard_timeout': False,
        'internal_failure': None,
        'stats': {
            #  'download': {
            #    'duration': 0.,
            #    'initial_number_items': 0,
            #    'initial_size': 0,
            #    'items_cold': '<large.pack()>',
            #    'items_hot': '<large.pack()>',
            #  },
            #  'upload': {
            #    'duration': 0.,
            #    'items_cold': '<large.pack()>',
            #    'items_hot': '<large.pack()>',
            #  },
        },
        'outputs_ref': None,
        'version': 3,
    }
    if root_dir:
        if not fs.isdir(root_dir):
            fs.makedirs(root_dir, 0700)
        prefix = u''
    else:
        root_dir = os.path.dirname(
            cache.cache_dir) if cache.cache_dir else None
        prefix = u'isolated_'
    run_dir = make_temp_dir(prefix + u'run', root_dir)
    out_dir = make_temp_dir(prefix + u'out', root_dir)
    tmp_dir = make_temp_dir(prefix + u'tmp', root_dir)
    try:
        start = time.time()
        bundle = isolateserver.fetch_isolated(isolated_hash=isolated_hash,
                                              storage=storage,
                                              cache=cache,
                                              outdir=run_dir)
        if not bundle.command:
            # Handle this as a task failure, not an internal failure.
            sys.stderr.write(
                '<The .isolated doesn\'t declare any command to run!>\n'
                '<Check your .isolate for missing \'command\' variable>\n')
            if os.environ.get('SWARMING_TASK_ID'):
                # Give an additional hint when running as a swarming task.
                sys.stderr.write('<This occurs at the \'isolate\' step>\n')
            result['exit_code'] = 1
            return result
        result['stats']['download'] = {
            'duration':
            time.time() - start,
            'initial_number_items':
            cache.initial_number_items,
            'initial_size':
            cache.initial_size,
            'items_cold':
            base64.b64encode(large.pack(sorted(cache.added))),
            'items_hot':
            base64.b64encode(
                large.pack(sorted(set(cache.linked) - set(cache.added)))),
        }

        change_tree_read_only(run_dir, bundle.read_only)
        cwd = os.path.normpath(os.path.join(run_dir, bundle.relative_cwd))
        command = bundle.command + extra_args
        file_path.ensure_command_has_abs_path(command, cwd)
        sys.stdout.flush()
        start = time.time()
        try:
            result['exit_code'], result['had_hard_timeout'] = run_command(
                process_command(command, out_dir), cwd, tmp_dir, hard_timeout,
                grace_period)
        finally:
            result['duration'] = max(time.time() - start, 0)
    except Exception as e:
        # An internal error occured. Report accordingly so the swarming task will be
        # retried automatically.
        logging.exception('internal failure: %s', e)
        result['internal_failure'] = str(e)
        on_error.report(None)
    finally:
        try:
            if leak_temp_dir:
                logging.warning(
                    'Deliberately leaking %s for later examination', run_dir)
            else:
                # On Windows rmtree(run_dir) call above has a synchronization effect: it
                # finishes only when all task child processes terminate (since a running
                # process locks *.exe file). Examine out_dir only after that call
                # completes (since child processes may write to out_dir too and we need
                # to wait for them to finish).
                if fs.isdir(run_dir):
                    try:
                        success = file_path.rmtree(run_dir)
                    except OSError as e:
                        logging.error('Failure with %s', e)
                        success = False
                    if not success:
                        print >> sys.stderr, (
                            'Failed to delete the run directory, forcibly failing\n'
                            'the task because of it. No zombie process can outlive a\n'
                            'successful task run and still be marked as successful.\n'
                            'Fix your stuff.')
                        if result['exit_code'] == 0:
                            result['exit_code'] = 1
                if fs.isdir(tmp_dir):
                    try:
                        success = file_path.rmtree(tmp_dir)
                    except OSError as e:
                        logging.error('Failure with %s', e)
                        success = False
                    if not success:
                        print >> sys.stderr, (
                            'Failed to delete the temporary directory, forcibly failing\n'
                            'the task because of it. No zombie process can outlive a\n'
                            'successful task run and still be marked as successful.\n'
                            'Fix your stuff.')
                        if result['exit_code'] == 0:
                            result['exit_code'] = 1

            # This deletes out_dir if leak_temp_dir is not set.
            start = time.time()
            result['outputs_ref'], success, cold, hot = delete_and_upload(
                storage, out_dir, leak_temp_dir)
            result['stats']['upload'] = {
                'duration': time.time() - start,
                'items_cold': base64.b64encode(large.pack(cold)),
                'items_hot': base64.b64encode(large.pack(hot)),
            }
            if not success and result['exit_code'] == 0:
                result['exit_code'] = 1
        except Exception as e:
            # Swallow any exception in the main finally clause.
            logging.exception('Leaking out_dir %s: %s', out_dir, e)
            result['internal_failure'] = str(e)
    return result