예제 #1
0
def isolated_to_hash(isolate_server, namespace, arg, algo, verbose):
  """Archives a .isolated file if needed.

  Returns the file hash to trigger and a bool specifying if it was a file (True)
  or a hash (False).
  """
  if arg.endswith('.isolated'):
    file_hash = isolated_archive(isolate_server, namespace, arg, algo, verbose)
    if not file_hash:
      on_error.report('Archival failure %s' % arg)
      return None, True
    return file_hash, True
  elif isolated_format.is_valid_hash(arg, algo):
    return arg, False
  else:
    on_error.report('Invalid hash %s' % arg)
    return None, False
예제 #2
0
def isolated_to_hash(arg, algo):
    """Archives a .isolated file if needed.

  Returns the file hash to trigger and a bool specifying if it was a file (True)
  or a hash (False).
  """
    if arg.endswith(".isolated"):
        file_hash = isolated_format.hash_file(arg, algo)
        if not file_hash:
            on_error.report("Archival failure %s" % arg)
            return None, True
        return file_hash, True
    elif isolated_format.is_valid_hash(arg, algo):
        return arg, False
    else:
        on_error.report("Invalid hash %s" % arg)
        return None, False
예제 #3
0
파일: cipd.py 프로젝트: rmoorman/luci-py
def get_client(service_url,
               package_template,
               version,
               cache_dir,
               timeout=None):
    """Returns a context manager that yields a CipdClient. A blocking call.

  Upon exit from the context manager, the client binary may be deleted
  (if the internal cache is full).

  Args:
    service_url (str): URL of the CIPD backend.
    package_template (str): package name template of the CIPD client.
    version (str): version of CIPD client package.
    cache_dir: directory to store instance cache, version cache
      and a hardlink to the client binary.
    timeout (int): if not None, timeout in seconds for this function.

  Yields:
    CipdClient.

  Raises:
    Error if CIPD client version cannot be resolved or client cannot be fetched.
  """
    timeoutfn = tools.sliding_timeout(timeout)

    # Package names are always lower case.
    # TODO(maruel): Assert instead?
    package_name = package_template.lower().replace('${platform}',
                                                    get_platform())

    # Resolve version to instance id.
    # Is it an instance id already? They look like HEX SHA1.
    if isolated_format.is_valid_hash(version, hashlib.sha1):
        instance_id = version
    elif ':' in version:  # it's an immutable tag, cache the resolved version
        # version_cache is {hash(package_name, tag) -> instance id} mapping.
        # It does not take a lot of disk space.
        version_cache = isolateserver.DiskCache(
            unicode(os.path.join(cache_dir, 'versions')),
            isolateserver.CachePolicies(0, 0, 300),
            hashlib.sha1,
            trim=True)
        with version_cache:
            version_cache.cleanup()
            # Convert (package_name, version) to a string that may be used as a
            # filename in disk cache by hashing it.
            version_digest = hashlib.sha1('%s\n%s' %
                                          (package_name, version)).hexdigest()
            try:
                with version_cache.getfileobj(version_digest) as f:
                    instance_id = f.read()
            except isolateserver.CacheMiss:
                instance_id = resolve_version(service_url,
                                              package_name,
                                              version,
                                              timeout=timeoutfn())
                version_cache.write(version_digest, instance_id)
    else:  # it's a ref, hit the backend
        instance_id = resolve_version(service_url,
                                      package_name,
                                      version,
                                      timeout=timeoutfn())

    # instance_cache is {instance_id -> client binary} mapping.
    # It is bounded by 5 client versions.
    instance_cache = isolateserver.DiskCache(
        unicode(os.path.join(cache_dir, 'clients')),
        isolateserver.CachePolicies(0, 0, 5),
        hashlib.sha1,
        trim=True)
    with instance_cache:
        instance_cache.cleanup()
        if instance_id not in instance_cache:
            logging.info('Fetching CIPD client %s:%s', package_name,
                         instance_id)
            fetch_url = get_client_fetch_url(service_url,
                                             package_name,
                                             instance_id,
                                             timeout=timeoutfn())
            _fetch_cipd_client(instance_cache, instance_id, fetch_url,
                               timeoutfn)

        # A single host can run multiple swarming bots, but ATM they do not share
        # same root bot directory. Thus, it is safe to use the same name for the
        # binary.
        cipd_bin_dir = unicode(os.path.join(cache_dir, 'bin'))
        binary_path = os.path.join(cipd_bin_dir, 'cipd' + EXECUTABLE_SUFFIX)
        if fs.isfile(binary_path):
            file_path.remove(binary_path)
        else:
            file_path.ensure_tree(cipd_bin_dir)

        with instance_cache.getfileobj(instance_id) as f:
            isolateserver.putfile(f, binary_path, 0511)  # -r-x--x--x

        _ensure_batfile(binary_path)

        yield CipdClient(binary_path,
                         package_name=package_name,
                         instance_id=instance_id,
                         service_url=service_url)
예제 #4
0
def get_client(service_url,
               package_template,
               version,
               cache_dir,
               timeout=None):
    """Returns a context manager that yields a CipdClient. A blocking call.

  Upon exit from the context manager, the client binary may be deleted
  (if the internal cache is full).

  Args:
    service_url (str): URL of the CIPD backend.
    package_template (str): package name template of the CIPD client.
    version (str): version of CIPD client package.
    cache_dir: directory to store instance cache, version cache
      and a hardlink to the client binary.
    timeout (int): if not None, timeout in seconds for this function.

  Yields:
    CipdClient.

  Raises:
    Error if CIPD client version cannot be resolved or client cannot be fetched.
  """
    timeoutfn = tools.sliding_timeout(timeout)

    # Package names are always lower case.
    # TODO(maruel): Assert instead?
    package_name = package_template.lower().replace('${platform}',
                                                    get_platform())

    # Resolve version to instance id.
    # Is it an instance id already? They look like HEX SHA1.
    if isolated_format.is_valid_hash(version, hashlib.sha1):
        instance_id = version
    elif ':' in version:  # it's an immutable tag, cache the resolved version
        # version_cache is {hash(package_name, tag) -> instance id} mapping.
        # It does not take a lot of disk space.
        version_cache = local_caching.DiskContentAddressedCache(
            six.text_type(os.path.join(cache_dir, 'versions')),
            local_caching.CachePolicies(
                # 1GiB.
                max_cache_size=1024 * 1024 * 1024,
                min_free_space=0,
                max_items=300,
                # 3 weeks.
                max_age_secs=21 * 24 * 60 * 60),
            trim=True)
        # Convert (package_name, version) to a string that may be used as a
        # filename in disk cache by hashing it.
        version_digest = hashlib.sha1('%s\n%s' %
                                      (package_name, version)).hexdigest()
        try:
            with version_cache.getfileobj(version_digest) as f:
                instance_id = f.read()
        except local_caching.CacheMiss:
            instance_id = resolve_version(service_url,
                                          package_name,
                                          version,
                                          timeout=timeoutfn())
            version_cache.write(version_digest, instance_id)
        version_cache.trim()
    else:  # it's a ref, hit the backend
        instance_id = resolve_version(service_url,
                                      package_name,
                                      version,
                                      timeout=timeoutfn())

    # instance_cache is {instance_id -> client binary} mapping.
    # It is bounded by 5 client versions.
    instance_cache = local_caching.DiskContentAddressedCache(
        six.text_type(os.path.join(cache_dir, 'clients')),
        local_caching.CachePolicies(
            # 1GiB.
            max_cache_size=1024 * 1024 * 1024,
            min_free_space=0,
            max_items=10,
            # 3 weeks.
            max_age_secs=21 * 24 * 60 * 60),
        trim=True)
    if instance_id not in instance_cache:
        logging.info('Fetching CIPD client %s:%s', package_name, instance_id)
        fetch_url = get_client_fetch_url(service_url,
                                         package_name,
                                         instance_id,
                                         timeout=timeoutfn())
        _fetch_cipd_client(instance_cache, instance_id, fetch_url, timeoutfn)

    # A single host can run multiple swarming bots, but they cannot share same
    # root bot directory. Thus, it is safe to use the same name for the binary.
    cipd_bin_dir = six.text_type(os.path.join(cache_dir, 'bin'))
    binary_path = os.path.join(cipd_bin_dir, 'cipd' + EXECUTABLE_SUFFIX)
    if fs.isfile(binary_path):
        # TODO(maruel): Do not unconditionally remove the binary.
        try:
            file_path.remove(binary_path)
        except WindowsError:  # pylint: disable=undefined-variable
            # See whether cipd.exe is running for crbug.com/1028781
            ret = subprocess42.call(['tasklist.exe'])
            if ret:
                logging.error('tasklist returns non-zero: %d', ret)
            raise
    else:
        file_path.ensure_tree(cipd_bin_dir)

    with instance_cache.getfileobj(instance_id) as f:
        isolateserver.putfile(f, binary_path, 0o511)  # -r-x--x--x

    _ensure_batfile(binary_path)

    yield CipdClient(binary_path,
                     package_name=package_name,
                     instance_id=instance_id,
                     service_url=service_url)
    instance_cache.trim()