Пример #1
0
 def __init__(self, **kwargs):
     self.platform = Platform_Meta('Singularity', 'Ⓢ')
     image = kwargs.get("image")
     tag = kwargs.get("tag")
     pwd = os.getcwd()
     if kwargs.get("working_dir") is not None:
         pwd = kwargs["working_dir"]
         os.chdir(pwd)
     print(f"Loading {self.platform.symbol} {self.platform.name}")
     if image and isinstance(image, str) and os.path.exists(image):
         self.image = image
     elif tag and isinstance(tag, str):  # pragma: no cover
         self.image = Client.pull(f"docker://{image}:{tag}",
                                  pull_folder=pwd)
     else:  # pragma: no cover
         try:
             self.image = Client.pull("shub://FCP-INDI/C-PAC",
                                      pull_folder=pwd)
         except Exception:
             try:
                 self.image = Client.pull(f"docker://fcpindi/c-pac:latest",
                                          pull_folder=pwd)
             except Exception:
                 raise OSError("Could not connect to Singularity")
     self.volumes = {}
     self.options = list(chain.from_iterable(
         kwargs["container_options"])) if bool(
             kwargs.get("container_options")) else []
     self._set_bindings(**kwargs)
Пример #2
0
 def singularity_pull(self, image):
     """Pulls an docker or singularity images from hub.
     """
     log.info('{}[{}] singularity pull {}'.format(
         self.msg_prefix, self.action['name'], image)
     )
     if not self.dry_run:
         sclient.pull(image, name=self.image_name)
Пример #3
0
def download_images(image_dir, image_url):
    image_name = 'su2_containers_fork_dev.sif'
    try:
        os.mkdir(image_dir)
    except:
        pass

    client.pull(image=image_url, name=image_name, pull_folder=image_dir)
    return image_name
Пример #4
0
 def singularity_pull(self, image):
     """Pulls an docker or singularity images from hub.
     """
     if not self.skip_pull:
         log.info('{}[{}] singularity pull {}'.format(
             self.msg_prefix, self.action['name'], image))
         if not self.dry_run:
             sclient.pull(image, name=self.image_name)
     else:
         if not self.singularity_exists():
             log.fail('The required singularity image {} was not found '
                      'locally.'.format(self.image_name))
Пример #5
0
def run_singularity_container_executable(container_image, executable_path,
                                         args_dict):
    """Launch an executable within a Singularity container.

    Args:
        container_image: A string containing the name of the container
            to pull.
        executable_path: A string containing the path of the executable
            to execute within the container.
        args_dict: A dictionary containing arguments and corresponding
            values.
    """
    # Import Singularity library
    from spython.main import Client as client

    # Pull the specified container. This pull in the latest version of
    # the container (with the specified tag if provided).
    singularity_image = client.pull(container_image)

    # Run the executable with the arguments
    # TODO how do we get logs?
    client.run(
        singularity_image,
        [executable_path, json.dumps(args_dict)],
    )

    # TODO give a real return value
    return "FINISHED"
Пример #6
0
def get_nvidia_devices(use_docker=True):
    """
    Returns a Dict[index, UUID] of all NVIDIA devices available to docker

    Arguments:
        use_docker: whether or not to use a docker container to run nvidia-smi. if not, use singularity

    Raises docker.errors.ContainerError if GPUs are unreachable,
           docker.errors.ImageNotFound if the CUDA image cannot be pulled
           docker.errors.APIError if another server error occurs
    """
    cuda_image = 'nvidia/cuda:9.0-cudnn7-devel-ubuntu16.04'
    nvidia_command = 'nvidia-smi --query-gpu=index,uuid --format=csv,noheader'
    if use_docker:
        client.images.pull(cuda_image)
        output = client.containers.run(
            cuda_image,
            nvidia_command,
            runtime=NVIDIA_RUNTIME,
            detach=False,
            stdout=True,
            remove=True,
        )
        gpus = output.decode()
    else:
        # use the singularity runtime to run nvidia-smi
        img = Client.pull('docker://' + cuda_image, pull_folder='/tmp')
        output = Client.execute(img, nvidia_command, options=['--nv'])
        if output['return_code'] != 0:
            raise SingularityError
        gpus = output['message']
    # Get newline delimited gpu-index, gpu-uuid list
    logger.info("GPUs: " + str(gpus.split('\n')[:-1]))
    return {gpu.split(',')[0].strip(): gpu.split(',')[1].strip() for gpu in gpus.split('\n')[:-1]}
Пример #7
0
def action_pull():
    '''the fetch view to perform the pull, and return a response
    '''

    # Ensure uri appears once
    container = request.form.get('uri')  # ubuntu:latest
    uri = request.form.get('endpoint')  # docker://
    container = '%s%s' % (uri, container.replace(uri, ''))

    app.logger.info("PULL for %s" % container)

    # If nvidia is used, use sregistry client
    if 'nvidia' in uri:
        nvidia = app.sregistry._get_setting('SREGISTRY_NVIDIA_TOKEN')

        # Make sure we use the right client
        os.environ['SREGISTRY_CLIENT'] = uri.replace('://', '')
        os.environ.putenv('SREGISTRY_CLIENT', uri.replace('://', ''))
        from sregistry.main import get_client
        client = get_client(image=container)
        app.logger.info("Using client %s" % client.client_name)

        try:
            puller = client.pull(container, force=True)
        except:
            puller = '''ERROR: manifest unknown, or pull error. 
                            Use docker-compose logs web to see issue!'''

    else:
        # We will stream the response back!
        image, puller = Client.pull(container, stream=True, pull_folder='/tmp')
        puller = itertools.chain(puller, [image])

    return Response(puller, mimetype='text/plain')
Пример #8
0
    def __init__(self, mode, container_image, volumes, extra_kwargs):
        assert mode in ('docker', 'singularity')
        self.mode = mode

        if mode == 'docker':
            import docker
            client = docker.from_env()
            if extra_kwargs.get('requires_gpu', False):
                extra_kwargs.pop('requires_gpu')
                extra_kwargs["device_requests"] = [
                    docker.types.DeviceRequest(count=-1,
                                               capabilities=[['gpu']])
                ]

            # check if the image is already present locally
            repo_tags = []
            for image in client.images.list():
                repo_tags.extend(image.attrs['RepoTags'])

            if container_image not in repo_tags:
                client.images.pull(container_image)

            self.docker_container = client.containers.create(container_image,
                                                             tty=True,
                                                             volumes=volumes,
                                                             **extra_kwargs)

        elif mode == 'singularity':
            from spython.main import Client
            # load local image file if it exists, otherwise search dockerhub
            if Path(container_image).exists():
                self.singularity_image = container_image
            else:
                self.singularity_image = Client.pull(
                    f'docker://{container_image}')

            if not Path(self.singularity_image).exists():
                raise FileNotFoundError(
                    f'Unable to locate container image {container_image}')

            # bin options
            singularity_bind = ','.join([
                f'{volume_src}:{volume["bind"]}'
                for volume_src, volume in volumes.items()
            ])
            options = ['--bind', singularity_bind]

            # gpu options
            if extra_kwargs.get('requires_gpu', False):
                # only nvidia at the moment
                options += ['--nv']

            self.client_instance = Client.instance(self.singularity_image,
                                                   start=False,
                                                   options=options)
Пример #9
0
def test_pull_and_run(tmp_path):
    image = Client.pull("shub://vsoch/singularity-images",
                        pull_folder=str(tmp_path))
    print(image)
    assert os.path.exists(image)
    ext = 'sif' if Client.version_info().major >= 3 else 'simg'
    assert image == str(tmp_path / ('singularity-images.' + ext))

    result = Client.run(image)
    print(result)
    assert 'You say please, but all I see is pizza..' in result
Пример #10
0
    def pull_image(self, model, progress_stream=sys.stderr):
        if len(set(model.platforms) & {"shub", "library"}) == 0:
            if "singularity" in model.platforms:
                # It's a local image. Just check that it exists, and raise if
                # not.
                if not self.image_exists(model):
                    raise ValueError("Could not find local Singularity image at %s" % (model.reference,))
            else:
                raise ValueError("Only know how to pull from shub:// and library://"
                                " . This Singularity model does not come from "
                                "either repository.")

        return Client.pull(image="%s://%s" % (model.repository, model.reference))
 def _download(self, image_spec: str):
     logger.debug('Downloading image %s', image_spec)
     try:
         # stream=True for singularity doesnt return progress or anything really - for now no progress
         self._downloading[image_spec]['message'] = "Starting download"
         img = Client.pull(image_spec, pull_folder=self.image_folder)
         logger.debug('Download for image %s complete to %s', image_spec,
                      img)
         self._downloading[image_spec]['success'] = True
         self._downloading[image_spec]['message'] = "Downloaded image"
     except Exception as ex:
         logger.debug('Download for Singularity image %s failed: %s',
                      image_spec, ex)
         self._downloading[image_spec]['success'] = False
         self._downloading[image_spec][
             'message'] = "Can't download image: {}".format(ex)
Пример #12
0
def run_singularity_container_executable(uuid, container_image,
                                         executable_path, logs_path,
                                         args_dict):
    """Launch an executable within a Singularity container.

    Args:
        uuid: A string containing the uuid of the job being run.
        container_image: A string containing the name of the container
            to pull.
        executable_path: A string containing the path of the executable
            to execute within the container.
        logs_path: A string (or None) containing the path of the
            directory containing the relevant logs within the container.
        args_dict: A dictionary containing arguments and corresponding
            values.
    """
    # Import Singularity library
    from spython.main import Client as client

    # Pull the specified container. This pull in the latest version of
    # the container (with the specified tag if provided).
    singularity_image = client.pull(
        image=container_image,
        pull_folder=os.environ['WORKER_SINGULARITY_IMAGES_DIRECTORY'],
    )

    # Run the executable with the arguments
    if logs_path is None:
        bind_option = None
    else:
        # Create the host path. This is required by the Singularity
        # library (though not the Docker library)
        host_path = os.path.join(os.environ['WORKER_LOGS_DIRECTORY'], uuid)
        os.makedirs(host_path, exist_ok=True)

        # Build the bind option to pass on to Singularity
        bind_option = host_path.rstrip('/') + ":" + logs_path.rstrip('/')

    client.execute(
        image=singularity_image,
        command=[executable_path, json.dumps(args_dict)],
        bind=bind_option,
    )

    # TODO give a real return value
    return "FINISHED"
Пример #13
0
def _pull(self,
          file_name,
          names,
          save=True,
          force=False,
          uri="docker://",
          **kwargs):
    """pull an image from a docker hub. This is a (less than ideal) workaround
       that actually does the following:

       - creates a sandbox folder
       - adds docker layers, metadata folder, and custom metadata to it
       - converts to a squashfs image with build

    the docker manifests are stored with registry metadata.
 
    Parameters
    ==========
    images: refers to the uri given by the user to pull in the format
    <collection>/<namespace>. You should have an API that is able to 
    retrieve a container based on parsing this uri.
    file_name: the user's requested name for the file. It can 
               optionally be None if the user wants a default.
    save: if True, you should save the container to the database
          using self.add()
    
    Returns
    =======
    finished: a single container path, or list of paths
    """

    # Use Singularity to build the image, based on user preference
    if file_name is None:
        file_name = self._get_storage_name(names)

    # Determine if the user already has the image
    if os.path.exists(file_name) and force is False:
        bot.exit("Image exists! Remove first, or use --force to overwrite")

    digest = names["version"] or names["tag"]

    # Build from sandbox, prefix with sandbox
    sandbox = get_tmpdir(prefix="sregistry-sandbox")

    # First effort, get image via Sregistry
    layers = self._download_layers(names["url"], digest)

    # This is the url where the manifests were obtained
    url = self._get_manifest_selfLink(names["url"], digest)

    # Add environment to the layers
    envtar = self._get_environment_tar()
    layers = [envtar] + layers

    # Create singularity image from an empty folder
    for layer in layers:
        bot.info("Exploding %s" % layer)
        result = extract_tar(layer, sandbox, handle_whiteout=True)
        if result["return_code"] != 0:
            bot.exit(result["message"])

    sudo = kwargs.get("sudo", False)

    # Build from a sandbox (recipe) into the image_file (squashfs)
    image_file = Singularity.build(image=file_name, recipe=sandbox, sudo=sudo)

    # Fall back to using Singularity
    if image_file is None:
        bot.info("Downloading with native Singularity, please wait...")
        image = file_name.replace("docker://", uri)
        image_file = Singularity.pull(image, pull_folder=sandbox)

    # Save to local storage
    if save is True:

        # Did we get the manifests?
        manifests = {}
        if hasattr(self, "manifests"):
            manifests = self.manifests

        container = self.add(image_path=image_file,
                             image_uri=names["uri"],
                             metadata=manifests,
                             url=url)

        # When the container is created, this is the path to the image
        image_file = container.image

    if os.path.exists(image_file):
        bot.debug("Retrieved image file %s" % image_file)
        bot.custom(prefix="Success!", message=image_file)

    # Clean up sandbox
    shutil.rmtree(sandbox)

    return image_file
Пример #14
0
    def pull_image(self, output_name=None, force=False):

        self.image_installed = False

        # the name must be valid. we use _ to separate name and version for the
        # singularity filemane but the image have a tag (version) and name
        # separated by a :

        # Our registry uses underscore. The output filename should use _ as well
        # However, for users and image stored on sylabs or singularity hub, we
        # use the character :

        # let us first retrieve the image and save it in a temporary file.
        # we keep the original name by only replacing the : with underscore so
        # that we can use ImageReader class to help us later on.
        if ":" in self.image_name:
            logger.info(f"Looking for {self.image_name}...")
            # e.g. fastqc:0.11.9
            registry_name = self.image_name  #.replace(":", "_")

            if self.image_name not in self.registry.registry.keys():
                logger.critical(
                    "invalid image name provided: {}. type 'damona list'".
                    format(self.image_name))
                guess = self.image_name.split(":")[0][0:4]
                # here we reverse x to start from the end and replace the last _
                # by :
                guesses = [
                    x[::-1].replace("_", ":", 1)[::-1]
                    for x in self.registry.registry.keys()
                    if x.startswith(guess)
                ]
                logger.critical("Maybe you meant one of: {}".format(guesses))
                sys.exit(1)
        else:
            from damona.registry import Software
            r = Software(self.image_name).releases
            latest = r.last_release
            logger.info(
                f"No version found after {self.image_name} (e.g. fastqc:0.11.8)."
                + f" Installing latest version {latest}")
            registry_name = self.image_name
            # we look only at the prefix name, not the tag. so we should get the
            # registry names from self.registry that have the prefix in common,
            # then extract the versions, and figure out the most recent.

        registry_name = self.registry.find_candidate(registry_name)
        if registry_name is None:
            logger.critical(
                f"No image found for {self.image_name}. Make sure it is correct using 'damona search' command"
            )
            sys.exit(1)

        download_name = self.registry.registry[registry_name].download

        # get metadata from the registry recipe
        info = self.registry.registry[registry_name]
        logger.info(f"{info}")

        if info.binaries:
            self.binaries = info.binaries
        else:
            logger.warning(
                f"No binaries field found in registry of {registry_name}")
            self.binaries = [self.input_image.guessed_executable]

        # target file is stored in output_name variable
        if output_name is None:
            output_name = registry_name.replace(":", "_") + ".img"
        # here we check whether the image or binaries are already present.
        # if md5 is already provided, and image exists, nothing to copy
        if info.md5sum:
            if os.path.exists(self.images_directory / output_name):
                from easydev import md5
                md5_target = md5(self.images_directory / output_name)

                if md5_target == info.md5sum:
                    logger.info(
                        "Remote image and local image are identical, no need to download/pull again"
                    )
                    self.input_image = ImageReader(self.images_directory /
                                                   output_name)
                    self.image_installed = True
                    return
        else:
            logger.warning(
                f"md5 field not found or not filled in {registry_name}."
                f"To be fixed in https://github.com/damona/damona/recipes/{self.image_name}/registry.yaml "
            )

        # now that we have the registry name, we can download the image
        logger.info("Downloading {}".format(download_name))

        # By default we downlaods from syslab.
        # if not found, one can provide an URL
        pull_folder = self.images_directory / "damona_buffer"

        if self.from_url:
            # The client does not support external https link other than
            # docker, library, shub.
            cmd = f"singularity pull --dir {pull_folder} "
            if force:
                cmd += " --force "
            cmd += f"{download_name}"
            subprocess.call(cmd.split())
        else:

            if download_name.startswith("https://"):
                print(f"downloading into {pull_folder} {output_name}")
                from urllib.request import urlretrieve
                urlretrieve(download_name,
                            filename=str(pull_folder / output_name))
                # wget.download(download_name, str(pull_folder / output_name))

            else:  # use singularity
                Client.pull(str(download_name),
                            name=output_name,
                            pull_folder=pull_folder,
                            force=force)
        logger.info(f"File {self.image_name} uploaded to {pull_folder}")

        # Read the image, checking everything is correct

        self.input_image = ImageReader(pull_folder / output_name)
        shortname = self.input_image.shortname
        try:
            logger.info(
                f"Copying into damona image directory: {self.images_directory}"
            )
            self.input_image.filename.rename(self.images_directory / shortname)
            self.input_image.filename = pathlib.Path(self.images_directory /
                                                     shortname)
        except FileNotFoundError:
            logger.warning("File not installed properly. Stopping")
            self.image_installed = False

        # check the md5 validity
        if info.md5sum:
            if info.md5sum != self.input_image.md5:
                logger.warning(
                    "MD5 of downloaded image does not match the expected md5 found in the "
                    f"registry of {registry_name}. The latter may be incorrect in damona and needs "
                    f"to be updated in https://github.com/damona/damona/recipes/{self.image_name}/registry.yaml "
                    "or the donwload was interrupted")

        self.image_installed = True
    read_file,
    write_file
)

from spython.main import Client
import unittest
import tempfile
import shutil
import json
import os

print("######################################################## test_reproduce")

# Pull images for all tests
tmpdir = tempfile.mkdtemp()
image1 = Client.pull('docker://ubuntu:14.04', pull_folder=tmpdir)
image2 = Client.pull('docker://busybox:1', pull_folder=tmpdir)

class TestReproduce(unittest.TestCase):

    def setUp(self):
        self.pwd = get_installdir()
        self.tmpdir = tmpdir
        self.image1 = image1
        self.image2 = image2
        
    def tearDown(self):
        pass

    def test_get_image_hashes(self):
        from singularity.analysis.reproduce import get_image_hashes, get_image_hash
Пример #16
0
 def _pull_image(self):
     client.pull(image=self.img_url,
                 name=self.img_name,
                 pull_folder=self.img_dir)
     return
Пример #17
0
def run_singularity_container_command(
    uuid,
    container_image,
    command_to_run,
    logs_path,
    results_path,
    env_vars_list,
    args_dict,
):
    """Launch an executable within a Singularity container.

    Args:
        uuid: A string containing the uuid of the job being run.
        container_image: A string containing the name of the container
            to pull.
        command_to_run: A string containing the command to run.
        logs_path: A string (or None) containing the path of the
            directory containing the relevant logs within the container.
        results_path: A string (or None) containing the path of the
            directory containing any output files from the container.
        env_vars_list: A list of strings containing the environment
            variable names for the worker to consume from its
            environment.
        args_dict: A dictionary containing arguments and corresponding
            values.

    Raises:
        KeyError: An environment variable specified was not available in
            the worker's environment.
        SingularityPullFailure: The Singularity pull could not complete
            with the specified timeout and number of retries.
    """
    # Import Singularity library
    from spython.main import Client as client

    # Pull the specified container. This pull in the latest version of
    # the container (with the specified tag if provided).
    timeout = int(os.environ["SINGULARITY_PULL_TIMEOUT"])
    num_retries = int(os.environ["SINGULARITY_PULL_RETRIES"])

    # Put a timeout on the client pull method
    client.pull = timeout_decorator.timeout(timeout,
                                            timeout_exception=StopIteration)(
                                                client.pull)

    for retry in range(num_retries):
        try:
            singularity_image = client.pull(
                image=container_image,
                pull_folder=os.environ["WORKER_SINGULARITY_IMAGES_DIRECTORY"],
                name_by_commit=True,
            )

            break
        except StopIteration:
            # If this is the last retry, raise an exception to indicate
            # a failed job
            if retry == num_retries - 1:
                raise SingularityPullFailure(
                    ("Could not pull {image_url} within "
                     "{timeout} seconds after {num_retries} retries.").format(
                         image_url=container_image,
                         timeout=timeout,
                         num_retries=num_retries,
                     ))

    # Find out where to put the logs
    if logs_path is None:
        bind_option = []
    else:
        # Create the host logs path. This is required by the Singularity
        # library (though not the Docker library)
        host_logs_path = os.path.join(os.environ["WORKER_LOGS_DIRECTORY"],
                                      uuid)

        create_local_directory(host_logs_path)

        # Build the bind option to pass on to Singularity
        bind_option = [
            host_logs_path.rstrip("/") + ":" + logs_path.rstrip("/")
        ]

    # Find out where to put the results
    if results_path is not None:
        # Create the host results path
        host_results_path = os.path.join(
            os.environ["WORKER_RESULTS_DIRECTORY"], uuid)

        create_local_directory(host_results_path)

        # Build the bind option to pass on to Singularity
        bind_option += [
            host_results_path.rstrip("/") + ":" + results_path.rstrip("/")
        ]

    # Check for required environment variables. Note that by default
    # Singularity containers have access to their outside environment
    # variables, so we don't need to pass them along explicitly like we
    # need to for a Docker container.
    try:
        # Test to see that all keys are defined
        {key: os.environ[key] for key in env_vars_list}
    except KeyError as e:
        raise KeyError(
            "Environment variable %s not present in the worker's environment!"
            % e)

    # Pass along the job's UUID
    os.environ["JOB_UUID"] = uuid

    # Compose the command to run
    command = shlex.split(command_to_run)

    if args_dict:
        command += [json.dumps(args_dict)]

    # Run the executable
    iter_ = client.execute(image=singularity_image,
                           command=command,
                           bind=bind_option,
                           stream=True)

    # Okay, here's some magic. The issue is that without stream=True in
    # the above call, there's no way of determining the return code of
    # the above operation, and so no way of knowing whether it failed.
    # However, with stream=True, it'll raise a
    # subprocess.CalledProcessError exception for any non-zero return
    # code. Great! But before we can get that exception triggered we
    # need to iterate through all of the command's stdout, which is what
    # the below (seemingly useless) loop does.
    for _ in iter_:
        pass
Пример #18
0
 def singularity_pull(self, image):
     """Pulls an docker or singularity images from hub.
     """
     Client.pull(image)
Пример #19
0
def main():
    '''main is the entrypoint to run a container comparison.
    '''

    parser = get_parser()

    try:
        args = parser.parse_args()
    except:
        sys.exit(0)

    if args.containers in [None, '', []]:
        print('Please provide a list of one or more containers to compare.')

# Step 1: Extraction of files

    print('1. Staring extraction for %s containers.' % len(args.containers))

    # We will save lists of files for comparison
    data = []

    for container in args.containers:

        # if the file exists, assume it's singularity

        func = run_analyze

        if os.path.exists(container):
            print('Found Singularity container file %s' % container)

        # If it starts with shub:// or docker:// we want to singularity pull

        if re.search('^(docker|shub)[://]', container):
            print('Pulling Singularity container %s' % container)
            container = Client.pull(container, pull_folder='/tmp')

        # Otherwise, must be docker container

        else:
            func = run_container_diff

        # Prefix of container for output
        name = os.path.basename(container)

        # Just generate files
        output_files = os.path.join(output, '%s-files.json' % name)

        # Run the analyze-singularity.sh for each of files and packages
        if not os.path.exists(output_files):
            print("Performing Extraction for %s" % container)
            dest = func(container, dest=output_files)
        else:
            dest = output_files
        print(dest)
        data.append(dest)


# Step 2: Generation of Web Interfaces

    print('2. Calculating comparisons')
    scores = pandas.DataFrame()

    # Lookup for files
    lookup = dict()
    htmls = dict()

    for d in data:
        datum = json.load(open(d, 'r'))
        osname = os.path.basename(d).replace('-files.json', '')
        files = []
        for f in datum[0]['Analysis']:
            files.append(f['Name'])

        lookup[osname] = files

    # Now calculate differences (and html tree) for each.
    for name1, files1 in lookup.items():
        for name2, files2 in lookup.items():

            # browser can have trouble with weird characters
            name = ("%s-%s" % (name1, name2)).replace(':',
                                                      '').replace('/', '-')

            # Calculate the score in matrix
            comparison = compare_lists(files1, files2)
            score = compare_files(files1, files2)
            scores.loc[name1, name2] = score

            # Create labels lookup to show which were added and removed
            labels = dict()
            allfiles = set(files1).union(set(files2))
            for afile in allfiles:
                if afile in comparison['shared']: labels[afile] = 'shared'
                elif afile in comparison['added']: labels[afile] = 'added'
                elif afile in comparison['removed']: labels[afile] = 'removed'

            # Generate tree that shows added and subtracted nodes
            tree = make_container_tree(allfiles, labels=labels)
            html = get_template(
                'container_tree', {
                    '{{ files | safe }}': json.dumps(tree['files']),
                    '{{ graph | safe }}': json.dumps(tree['graph']),
                    '{{ container_name }}': "%s --> %s Tree" % (name1, name2)
                })

            html_file = '%s/%s.html' % (output, name)
            htmls['%s vs. %s' % (name1, name2)] = html_file
            with open(html_file, 'w') as filey:
                filey.writelines(html)

    # Create web plot
    values = ',\n'.join(
        [str(values.tolist()) for row, values in scores.items()])

    # Write list of html files
    extra = '<br><div><h2>View Comparison</h2><ul>'
    for name, html_file in htmls.items():
        extra += '<li><a href="%s">%s</a></li>\n' % (
            os.path.basename(html_file), name)
    extra += '</ul></div></body>'

    # Plot via html
    template = get_template(
        'heatmap', {
            '{{ title }}': "Similarity of Containers based on Filesystem",
            '{{ data }}': values,
            '{{ X }}': str(scores.index.tolist()),
            '{{ Y }}': str(scores.columns.tolist()),
            '</body>': extra
        })

    # Save scores for user as data frame
    scores.to_csv('%s/information-coefficient-scores.tsv' % output, sep='\t')

    with open('%s/index.html' % output, 'w') as filey:
        filey.writelines(template)

    # Open browser there
    os.chdir(output)
    Handler = http.server.SimpleHTTPRequestHandler
    with socketserver.TCPServer(("", 8888), Handler) as httpd:
        print("Open browser to http://0.0.0.0:8888")
        httpd.serve_forever()
Пример #20
0
def docker_container(tmp_path_factory):
    folder = tmp_path_factory.mktemp("docker-img")
    return folder, Client.pull("docker://busybox:1.30.1",
                               pull_folder=str(folder))
Пример #21
0
def _pull(self, file_name, names, save=True, force=False, **kwargs):
    '''pull an image from aws. This is a (less than ideal) workaround
       that actually does the following:

       - creates a sandbox folder
       - adds docker layers from S3
       - converts to a squashfs image with build
 
    Parameters
    ==========
    images: refers to the uri given by the user to pull in the format
    <collection>/<namespace>. You should have an API that is able to 
    retrieve a container based on parsing this uri.
    file_name: the user's requested name for the file. It can 
               optionally be None if the user wants a default.
    save: if True, you should save the container to the database
          using self.add()
    
    Returns
    =======
    finished: a single container path, or list of paths
    '''

    # Use Singularity to build the image, based on user preference
    if file_name is None:
        file_name = self._get_storage_name(names)

    # Determine if the user already has the image
    if os.path.exists(file_name) and force is False:
        bot.error('Image exists! Remove first, or use --force to overwrite')
        sys.exit(1)

    digest = names['version'] or names['tag']

    # Build from sandbox
    sandbox = get_tmpdir(prefix="sregistry-sandbox")

    # First effort, get image via Sregistry
    layers, url = self._download_layers(names['url'], digest)

    # Add environment to the layers
    envtar = self._get_environment_tar()
    layers = [envtar] + layers

    # Create singularity image from an empty folder
    for layer in layers:
        bot.info('Exploding %s' % layer)
        result = extract_tar(layer, sandbox, handle_whiteout=True)
        if result['return_code'] != 0:
            bot.error(result['message'])
            sys.exit(1)

    sudo = kwargs.get('sudo', False)

    # Build from a sandbox (recipe) into the image_file (squashfs)
    image_file = Singularity.build(image=file_name, recipe=sandbox, sudo=sudo)

    # Fall back to using Singularity
    if image_file is None:
        bot.info('Downloading with native Singularity, please wait...')
        image = image.replace('aws://', 'docker://')
        image_file = Singularity.pull(image, pull_folder=sandbox)

    # Save to local storage
    if save is True:

        # Did we get the manifests?
        manifests = {}
        if hasattr(self, 'manifest'):
            manifest = self.manifest

        container = self.add(image_path=image_file,
                             image_uri=names['uri'],
                             metadata=manifest,
                             url=url)

        # When the container is created, this is the path to the image
        image_file = container.image

    if os.path.exists(image_file):
        bot.debug('Retrieved image file %s' % image_file)
        bot.custom(prefix="Success!", message=image_file)

    # Clean up sandbox
    shutil.rmtree(sandbox)

    return image_file